[
  {
    "path": ".github/workflows/contributors.yaml",
    "content": "name: Add contributors\non:\n  schedule:\n    - cron:  '20 20 * * *'\n\njobs:\n  add-contributors:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v2\n    - uses: BobAnkh/add-contributors@master\n      with:\n        CONTRIBUTOR: '## Contribuidores'\n        COLUMN_PER_ROW: '6'\n        ACCESS_TOKEN: ${{secrets.GITHUB_TOKEN}}\n        IMG_WIDTH: '100'\n        FONT_SIZE: '14'\n        PATH: '/README.md'\n        COMMIT_MESSAGE: 'docs(README): update contributors'\n        AVATAR_SHAPE: 'round'"
  },
  {
    "path": ".gitignore",
    "content": "# build output\ndist/\n\n# generated types\n.astro/\n\n# dependencies\nnode_modules/\n\n# logs\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n#locks\nbun.lockb\npnpm-lock.yaml\npackage-lock.json\n\n# environment variables\n.env\n.env.production\n.env.local\n\n# macOS-specific files\n.DS_Store\n\n# jetbrains setting folder\n.idea/\n"
  },
  {
    "path": ".vercel/project.json",
    "content": "{\"projectId\":\"prj_SsanVSwAoWqNeWqovW1OdwWn8CrZ\",\"orgId\":\"team_pzEis5cENnPrEa0YhyEfJ7Ek\"}"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\"astro-build.astro-vscode\"],\n  \"unwantedRecommendations\": []\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"command\": \"./node_modules/.bin/astro dev\",\n      \"name\": \"Development server\",\n      \"request\": \"launch\",\n      \"type\": \"node-terminal\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"cSpell.words\": [\"Coméntalo\", \"infojobs\", \"jovenes\", \"Twitea\"]\n}\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Código de Conducta para Contribuyentes\n\n## Nuestro compromiso\n\nNosotros, como miembros, contribuyentes y administradores nos comprometemos a hacer de la participación en nuestra comunidad una experiencia libre de acoso para todos, independientemente de la edad, dimensión corporal, discapacidad visible o invisible, etnicidad, características sexuales, identidad y expresión de género, nivel de experiencia, educación, nivel socio-económico, nacionalidad, apariencia personal, raza, religión, o identidad u orientación sexual.\n\nNos comprometemos a actuar e interactuar de maneras que contribuyan a una comunidad abierta, acogedora, diversa, inclusiva y sana.\n\n## Nuestros estándares\n\nEjemplos de comportamiento que contribuyen a crear un ambiente positivo:\n\n* Demostrar empatía y amabilidad ante otras personas\n* Respeto a diferentes opiniones, puntos de vista y experiencias\n* Dar y aceptar adecuadamente retroalimentación constructiva\n* Aceptar la responsabilidad y disculparse ante quienes se vean afectados por nuestros errores, aprendiendo de la experiencia\n* Centrarse en lo que sea mejor no sólo para nosotros como individuos, sino para la comunidad en general\n\nEjemplos de comportamiento inaceptable:\n\n* El uso de lenguaje o imágenes sexualizadas, y aproximaciones o atenciones sexuales de cualquier tipo\n* Comentarios despectivos (_trolling_), insultantes o derogatorios, y ataques personales o políticos\n* El acoso en público o privado\n* Publicar información privada de otras personas, tales como direcciones físicas o de correo electrónico, sin su permiso explícito\n* Otras conductas que puedan ser razonablemente consideradas como inapropiadas en un entorno profesional\n\n## Aplicación de las responsabilidades\n\nLos administradores de la comunidad son responsables de aclarar y hacer cumplir nuestros estándares de comportamiento aceptable y tomarán acciones apropiadas y correctivas de forma justa en respuesta a cualquier comportamiento que consideren inapropiado, amenazante, ofensivo o dañino.\n\nLos administradores de la comunidad tendrán el derecho y la responsabilidad de eliminar, editar o rechazar comentarios, _commits_, código, ediciones de páginas de wiki, _issues_ y otras contribuciones que no se alineen con este Código de Conducta, y comunicarán las razones para sus decisiones de moderación cuando sea apropiado.\n\n## Alcance\n\nEste código de conducta aplica tanto a espacios del proyecto como a espacios públicos donde un individuo esté en representación del proyecto o comunidad. Ejemplos de esto incluyen el uso de la cuenta oficial de correo electrónico, publicaciones a través de las redes sociales oficiales, o presentaciones con personas designadas en eventos en línea o no.\n\n## Aplicación\n\nInstancias de comportamiento abusivo, acosador o inaceptable de otro modo podrán ser reportadas a los administradores de la comunidad responsables del cumplimiento a través de <miduga@gmail.com>. Todas las quejas serán evaluadas e investigadas de una manera puntual y justa.\n\nTodos los administradores de la comunidad están obligados a respetar la privacidad y la seguridad de quienes reporten incidentes.\n\n## Guías de Aplicación\n\nLos administradores de la comunidad seguirán estas Guías de Impacto en la Comunidad para determinar las consecuencias de cualquier acción que juzguen como un incumplimiento de este Código de Conducta:\n\n### 1. Corrección\n\n**Impacto en la Comunidad**: El uso de lenguaje inapropiado u otro comportamiento considerado no profesional o no acogedor en la comunidad.\n\n**Consecuencia**: Un aviso escrito y privado de los administradores de la comunidad, proporcionando claridad alrededor de la naturaleza de este incumplimiento y una explicación de por qué el comportamiento es inaceptable. Una disculpa pública podría ser solicitada.\n\n### 2. Aviso\n\n**Impacto en la Comunidad**: Un incumplimiento causado por un único incidente o por una cadena de acciones.\n\n**Consecuencia**: Un aviso con consecuencias por comportamiento prolongado. No se interactúa con las personas involucradas, incluyendo interacción no solicitada con quienes se encuentran aplicando el Código de Conducta, por un período específico de tiempo. Esto incluye evitar las interacciones en espacios de la comunidad, así como a través de canales externos como las redes sociales. Incumplir estos términos puede conducir a una expulsión temporal o permanente.\n\n### 3. Expulsión temporal\n\n**Impacto en la Comunidad**: Una serie de incumplimientos de los estándares de la comunidad, incluyendo comportamiento inapropiado continuo.\n\n**Consecuencia**: Una expulsión temporal de cualquier forma de interacción o comunicación pública con la comunidad durante un intervalo de tiempo especificado. No se permite interactuar de manera pública o privada con las personas involucradas, incluyendo interacciones no solicitadas con quienes se encuentran aplicando el Código de Conducta, durante este período. Incumplir estos términos puede conducir a una expulsión permanente.\n\n### 4. Expulsión permanente\n\n**Impacto en la Comunidad**: Demostrar un patrón sistemático de incumplimientos de los estándares de la comunidad, incluyendo conductas inapropiadas prolongadas en el tiempo, acoso de individuos, o agresiones o menosprecio a grupos de individuos.\n\n**Consecuencia**: Una expulsión permanente de cualquier tipo de interacción pública con la comunidad del proyecto.\n\n## Atribución\n\nEste Código de Conducta es una adaptación del [Contributor Covenant][homepage], versión 2.0,\ndisponible en https://www.contributor-covenant.org/es/version/2/0/code_of_conduct.html\n\nLas Guías de Impacto en la Comunidad están inspiradas en la [escalera de aplicación del código de conducta de Mozilla](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nPara respuestas a las preguntas frecuentes de este código de conducta, consulta las FAQ en\nhttps://www.contributor-covenant.org/faq. Hay traducciones disponibles en\nhttps://www.contributor-covenant.org/translations."
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribuir a Landing de InfoJobs\n\nPrimero que nada, ¡gracias por tomarte el tiempo para contribuir! ❤️\n\nSe anima y valora todo tipo de contribuciones. Consulta la [Tabla de Contenidos](#tabla-de-contenidos) para conocer las diferentes maneras de ayudar y detalles sobre cómo maneja este proyecto las contribuciones. Asegúrate de leer la sección relevante antes de hacer tu contribución, lo que facilitará mucho el trabajo a los mantenedores y mejorará la experiencia para todos los involucrados. La comunidad espera tus contribuciones con entusiasmo. 🎉\n\n> Y si te gusta el proyecto pero no tienes tiempo para contribuir, no te preocupes. Hay otras formas sencillas de apoyar el proyecto y mostrar tu aprecio, las cuales también agradeceríamos mucho:\n> - Dale una estrella al proyecto\n> - Twitea sobre él\n> - Menciona este proyecto en el README de tu proyecto\n> - Coméntalo en reuniones locales y cuéntaselo a tus amigos/colegas\n\n<!-- omit in toc -->\n## Tabla de Contenidos\n\n- [Código de Conducta](#código-de-conducta)\n- [Tengo una Pregunta](#tengo-una-pregunta)\n- [Quiero Contribuir](#quiero-contribuir)\n- [Reportar Errores](#reportar-errores)\n- [Sugerir Mejoras](#sugerir-mejoras)\n- [Tu Primera Contribución de Código](#tu-primera-contribución-de-código)\n- [Mensajes de Commit](#mensajes-de-commit)\n\n\n## Código de Conducta\n\nEste proyecto y todos los que participan en él están regidos por el [Código de Conducta de Landing de InfoJobs](https://github.com/midudev/landing-infojobs/blob/main/CODE_OF_CONDUCT.md). Al participar, se espera que cumplas con este código. Por favor, reporta cualquier comportamiento inaceptable a <miduga@gmail.com>.\n\n## Tengo una Pregunta\n\n> Si quieres hacer una pregunta, asumimos que has leído la [Documentación](https://github.com/midudev/landing-infojobs) disponible.\n\nAntes de hacer una pregunta, lo mejor es buscar [Issues](https://github.com/midudev/landing-infojobs/issues) existentes que puedan ayudarte. En caso de encontrar un issue adecuado y aún necesitar aclaraciones, puedes escribir tu pregunta en ese issue. También es aconsejable buscar respuestas en internet primero.\n\nSi después de esto todavía sientes la necesidad de hacer una pregunta y necesitas aclaración, te recomendamos lo siguiente:\n\n- Abre un [Issue](https://github.com/midudev/landing-infojobs/issues/new).\n- Proporciona el mayor contexto posible sobre el problema que estás enfrentando.\n- Proporciona versiones del proyecto y la plataforma (Node.js, npm, etc.), dependiendo de lo que parezca relevante.\n\nNos encargaremos del issue lo antes posible.\n\n## Quiero Contribuir\n\n> ### Aviso Legal <!-- omit in toc -->\n> Al contribuir a este proyecto, debes aceptar que eres el autor del 100% del contenido, que tienes los derechos necesarios para el contenido, y que el contenido que contribuyas puede ser proporcionado bajo la licencia del proyecto.\n\n### Reportar Errores\n\n#### Antes de Enviar un Informe de Error\n\nUn buen informe de error no debería dejar a otros necesitando más información. Por lo tanto, te pedimos que investigues cuidadosamente, recopiles información y describas el problema en detalle en tu informe. Completa los siguientes pasos para ayudarnos a solucionar cualquier error potencial lo más rápido posible.\n\n- Asegúrate de estar utilizando la última versión.\n- Verifica si el problema realmente es un error y no un problema de configuración (Asegúrate de haber leído la [documentación](https://github.com/midudev/landing-infojobs). Si buscas soporte, podrías consultar [esta sección](#tengo-una-pregunta)).\n- Para ver si otros usuarios han experimentado (y posiblemente resuelto) el mismo problema, verifica si ya existe un informe para ese error en el [rastreador de errores](https://github.com/midudev/landing-infojobs/issues?q=label%3Abug).\n- También asegúrate de buscar en internet (incluyendo Stack Overflow) para ver si usuarios fuera de la comunidad de GitHub han discutido el problema.\n- Recopila información sobre el error:\n  - Traza de pila (Stack trace)\n  - Sistema operativo, plataforma y versión (Windows, Linux, macOS, x86, ARM)\n  - Versión del intérprete, compilador, SDK, entorno de ejecución, gestor de paquetes, dependiendo de lo que parezca relevante.\n  - Posiblemente, tu entrada y salida\n  - ¿Puedes reproducir el problema de manera confiable? ¿Y también con versiones anteriores?\n\n#### ¿Cómo Enviar un Buen Informe de Error?\n\n> Nunca debes informar problemas relacionados con la seguridad, vulnerabilidades o errores que incluyan información sensible en el rastreador de issues o en otro lugar público. En su lugar, los errores sensibles deben ser enviados por correo electrónico a <miduga@gmail.com>.\n\nUtilizamos issues de GitHub para rastrear errores. Si encuentras un problema con el proyecto:\n\n- Abre un [Issue](https://github.com/midudev/landing-infojobs/issues/new). (Dado que en este punto no estamos seguros si es un error, te pedimos que no lo llames \"bug\" aún ni lo etiquetes).\n- Explica el comportamiento esperado y el comportamiento real.\n- Proporciona tanto contexto como sea posible y describe los *pasos para reproducir* que alguien más puede seguir para recrear el problema. Esto usualmente incluye tu código. Para buenos informes de error, deberías aislar el problema y crear un caso de prueba reducido.\n- Proporciona la información que recopilaste en la sección anterior.\n\nUna vez enviado:\n\n- El equipo del proyecto etiquetará el issue según corresponda.\n- Un miembro del equipo intentará reproducir el problema con los pasos proporcionados. Si no hay pasos para reproducir o no es obvio cómo hacerlo, el equipo te pedirá esos pasos y marcará el issue como `needs-repro`. Los errores con la etiqueta `needs-repro` no serán atendidos hasta que se puedan reproducir.\n- Si el equipo puede reproducir el problema, será etiquetado como `needs-fix`, además de posiblemente otras etiquetas (como `critical`), y el issue quedará disponible para ser [implementado por alguien](#tu-primera-contribución-de-código).\n\n### Sugerir Mejoras\n\nEsta sección te guiará en la presentación de una sugerencia de mejora para Landing de InfoJobs, **incluyendo nuevas características y mejoras menores de la funcionalidad existente**. Seguir estas pautas ayudará a los mantenedores y la comunidad a entender tu sugerencia y encontrar sugerencias relacionadas.\n\n#### Antes de Enviar una Mejora\n\n- Asegúrate de estar utilizando la última versión.\n- Lee la [documentación](https://github.com/midudev/landing-infojobs) detenidamente y verifica si la funcionalidad ya está cubierta, tal vez por una configuración individual.\n- Realiza una [búsqueda](https://github.com/midudev/landing-infojobs/issues) para ver si la mejora ya ha sido sugerida. Si es así, añade un comentario al issue existente en lugar de abrir uno nuevo.\n- Asegúrate de que tu idea encaje con el alcance y los objetivos del proyecto. Es tu responsabilidad hacer una fuerte argumentación para convencer a los desarrolladores del proyecto de los méritos de esta característica. Ten en cuenta que buscamos características que sean útiles para la mayoría de nuestros usuarios y no solo para un pequeño grupo. Si solo estás apuntando a una minoría de usuarios, considera escribir una biblioteca de complementos.\n\n#### ¿Cómo Enviar una Buena Sugerencia de Mejora?\n\nLas sugerencias de mejora se rastrean como [issues de GitHub](https://github.com/midudev/landing-infojobs/issues).\n\n- Usa un **título claro y descriptivo** para el issue que identifique la sugerencia.\n- Proporciona una **descripción paso a paso de la mejora sugerida** con tantos detalles como sea posible.\n- **Describe el comportamiento actual** y **explica qué comportamiento esperabas ver en su lugar** y por qué. En este punto, también puedes indicar qué alternativas no funcionan para ti.\n- Puedes **incluir capturas de pantalla y GIFs animados** que te ayuden a demostrar los pasos o señalar la parte relacionada con la sugerencia. Puedes usar [esta herramienta](https://www.cockos.com/licecap/) para grabar GIFs en macOS y Windows, y [esta herramienta](https://github.com/colinkeenan/silentcast) o [esta herramienta](https://github.com/GNOME/byzanz) en Linux.\n- **Explica por qué esta mejora sería útil** para la mayoría de los usuarios de Landing de InfoJobs. También puedes mencionar otros proyectos que hayan resuelto mejor el problema y que podrían servir de inspiración.\n\n### Tu Primera Contribución de Código\n\n¿Listo para contribuir con código? ¡Genial! A continuación, te mostramos cómo empezar:\n\n1. **Bifurca (Fork) el repositorio** en tu cuenta de GitHub.\n\n2. **Clona el repositorio bifurcado** en tu máquina local:\n   ```bash\n   git clone https://github.com/tu-usuario/landing-infojobs.git\n   ```\n\n3. **Crea una rama nueva** para tu contribución. Utiliza un nombre de rama descriptivo:\n   ```bash\n   git checkout -b nombre-de-tu-rama\n   ```\n4. **Haz tus cambios**. Asegúrate de seguir las pautas de codificación del proyecto y de que tus contribuciones sean claras y concisas. Si estás agregando una nueva característica, asegúrate de que tenga cobertura de pruebas.\n5. **Prueba tus cambios** para verificar que todo funcione correctamente:\n   ```bash\n   npm run preview\n   ```\n6. **Haz commit de tus cambios** siguiendo las convenciones de mensajes de commit (ver la sección [Mensajes de Commit](#mensajes-de-commit)).\n7. **Sube tu rama** a GitHub:\n   ```bash\n   git push origin nombre-de-tu-rama\n   ```\n8. **Abre un Pull Request (PR)** desde tu rama y describe claramente los cambios que has realizado. Si tu PR resuelve un issue existente, asegúrate de mencionarlo en la descripción.\n9. **Espera la revisión**. Un mantenedor revisará tu PR, te proporcionará comentarios y lo aprobará si está listo para ser fusionado.\n\n### Mensajes de Commit\n\nPara mantener un historial de cambios consistente y claro, utilizamos una convención para los mensajes de commit. El formato es el siguiente:\n\n```scss\ntipo(área): descripción corta [opcional]\n```\n\n- **tipo**: indica la naturaleza del cambio. Algunos ejemplos son:\n  - `feat`: una nueva característica para el proyecto.\n  - `fix`: corrección de errores.\n  - `docs`: cambios en la documentación.\n  - `style`: cambios que no afectan la lógica del código (formato, espacios, etc.).\n  - `refactor`: cambios en el código que no corrigen errores ni agregan funciones.\n  - `test`: agregar o corregir pruebas.\n  - `chore`: cambios en el proceso de construcción o herramientas auxiliares.\n- **área**: especifica la parte del proyecto que se ve afectada (por ejemplo, un archivo o módulo).\n- **descripción breve**: explica de manera concisa qué se ha hecho. Usa el modo imperativo (por ejemplo, \"agrega\", \"corrige\").\n- **descripción detallada opcional**: puede incluir más detalles sobre el commit.\n\n<br/>\n\n**Ejemplo de mensaje de commit:**\n   ```scss\n   docs(readme.md): add local install instructions\n   ```\n\nEste mensaje indica que se han añadido instrucciones de instalación local en el archivo `readme.md`.\n\n<br/>\n\n\n¡Gracias por contribuir! Tu ayuda hace una gran diferencia para el proyecto.\n\n<br/>\n\n\n## Atribución\n\nEsta guía está basada en **contributing-gen**. [¡Haz la tuya!](https://github.com/bttger/contributing-gen)\n"
  },
  {
    "path": "README.md",
    "content": "\n# Landing de InfoJobs\n\nEste proyecto es una landing page para InfoJobs, diseñada para proporcionar una presentación moderna y atractiva de la plataforma, destacando sus características y beneficios. La landing page busca captar la atención de los usuarios y motivarlos a explorar los servicios de InfoJobs, promoviendo una mejor experiencia de búsqueda de empleo.\n\n\n## Tech Stack\n\n![ASTRO](https://img.shields.io/badge/astro-%23E34F26.svg?style=for-the-badge&logo=astro&logoColor=white)\n\n![TailwindCSS](https://img.shields.io/badge/tailwindcss-%2338B2AC.svg?style=for-the-badge&logo=tailwind-css&logoColor=white)\n\n![TypeScript](https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white)\n\n\n## Contribuidores\n\n<table>\n<tr>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/midudev>\n            <img src=https://avatars.githubusercontent.com/u/1561955?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Miguel Ángel Durán/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Miguel Ángel Durán</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/luchofseven>\n            <img src=https://avatars.githubusercontent.com/u/82046975?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Luciano Fernández/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Luciano Fernández</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/andreasop01>\n            <img src=https://avatars.githubusercontent.com/u/124921019?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Andrea Llovera De Sousa/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Andrea Llovera De Sousa</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/diego-dev018>\n            <img src=https://avatars.githubusercontent.com/u/175571311?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Diego Ronaldo Sanchez/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Diego Ronaldo Sanchez</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/Melissa1221>\n            <img src=https://avatars.githubusercontent.com/u/121834468?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Melissa Iman Noriega/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Melissa Iman Noriega</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/jordigd20>\n            <img src=https://avatars.githubusercontent.com/u/60585963?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Jordi Gómez Devesa/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Jordi Gómez Devesa</b></sub>\n        </a>\n    </td>\n</tr>\n<tr>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/EduWTR>\n            <img src=https://avatars.githubusercontent.com/u/139919492?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Edu/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Edu</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/OctaEDLP00>\n            <img src=https://avatars.githubusercontent.com/u/42822581?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=DevMetal00/>\n            <br />\n            <sub style=\"font-size:14px\"><b>DevMetal00</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/alesdevux>\n            <img src=https://avatars.githubusercontent.com/u/76450853?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=alesdevux/>\n            <br />\n            <sub style=\"font-size:14px\"><b>alesdevux</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/DiegoT4l>\n            <img src=https://avatars.githubusercontent.com/u/128425675?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=DiegoT4l/>\n            <br />\n            <sub style=\"font-size:14px\"><b>DiegoT4l</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/gusCreator>\n            <img src=https://avatars.githubusercontent.com/u/147654561?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Luis Gustavo Sequeiros Condori/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Luis Gustavo Sequeiros Condori</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/javimata>\n            <img src=https://avatars.githubusercontent.com/u/2237207?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Javi Mata/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Javi Mata</b></sub>\n        </a>\n    </td>\n</tr>\n<tr>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/IzanMen>\n            <img src=https://avatars.githubusercontent.com/u/175528066?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Izan Sánchez Ginés/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Izan Sánchez Ginés</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/juanjk24>\n            <img src=https://avatars.githubusercontent.com/u/147955917?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Juan Cuellar/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Juan Cuellar</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/Anthonazo>\n            <img src=https://avatars.githubusercontent.com/u/118082256?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Anthony Moya Ochoa/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Anthony Moya Ochoa</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/MiguelVallina2002>\n            <img src=https://avatars.githubusercontent.com/u/93439131?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Miguel Vallina Samaniego/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Miguel Vallina Samaniego</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/KoenigDev>\n            <img src=https://avatars.githubusercontent.com/u/160176319?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Nunu/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Nunu</b></sub>\n        </a>\n    </td>\n    <td align=\"center\" style=\"word-wrap: break-word; width: 150.0; height: 150.0\">\n        <a href=https://github.com/astrobot-houston>\n            <img src=https://avatars.githubusercontent.com/u/108291165?v=4 width=\"100;\"  style=\"border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px\" alt=Houston (Bot)/>\n            <br />\n            <sub style=\"font-size:14px\"><b>Houston (Bot)</b></sub>\n        </a>\n    </td>\n</tr>\n</table>\n\n\n## Correr Localmente\n\nClona el proyecto\n\n```bash\ngit clone https://github.com/midudev/landing-infojobs.git\n```\n\nDirigete al directorio del proyecto\n\n```bash\ncd landing-infojobs\n```\n\nInstala las dependencias\n\n```bash\nnpm install\n```\n\nInicia el servidor\n\n```bash\nnpm run start\n```\n\n\n## Variables de entorno\n\nPara correr este proyecto, necesitarás agregar las siguientes variable de entorno `API_INFOJOBS_TOKEN` en tu archivo .env\n\n> [!NOTE]\n> Puedes conseguir el token en esta url [Developer Site InfoJobs](https://developer.infojobs.net/).\n> Debes loguearte con tu cuenta infojobs, y al crear una app, te darán tus credenciales.\n\n> [!WARNING]\n> Deshabilitado en este momento.\n\n## Contribuciones\n\nLas contribuciones son siempre bienvenidas.\n\nConsulta `contributing.md` para saber cómo empezar.\n\nPor favor, respete el `código de conducta` de este proyecto.\n\n"
  },
  {
    "path": "astro.config.mjs",
    "content": "// @ts-check\nimport { defineConfig } from 'astro/config';\n\nimport tailwind from '@astrojs/tailwind';\n\n// https://astro.build/config\nexport default defineConfig({\n  build: {\n    inlineStylesheets: 'always'\n  },\n  integrations: [tailwind()]\n});"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"landing-jovenes-infojobs\",\n  \"type\": \"module\",\n  \"version\": \"0.0.1\",\n  \"scripts\": {\n    \"dev\": \"astro dev\",\n    \"start\": \"astro dev\",\n    \"build\": \"astro check && astro build\",\n    \"preview\": \"astro preview\",\n    \"astro\": \"astro\"\n  },\n  \"dependencies\": {\n    \"@astrojs/check\": \"0.9.4\",\n    \"@astrojs/tailwind\": \"5.1.2\",\n    \"astro\": \"4.16.13\",\n    \"tailwindcss\": \"3.4.15\",\n    \"typescript\": \"5.6.3\"\n  }\n}\n"
  },
  {
    "path": "src/components/AdevintaInfo.astro",
    "content": "---\nconst LINKS = [\n  {\n    label: \"JobisJob\",\n    href: \"https://www.jobisjob.es/\",\n  },\n  {\n    label: \"Fotocasa\",\n    href: \"https://www.fotocasa.es/es\",\n  },\n  {\n    label: \"habitaclia\",\n    href: \"https://www.habitaclia.com/\",\n  },\n  {\n    label: \"Coches.net\",\n    href: \"https://www.coches.net/\",\n  },\n  {\n    label: \"Motos.net\",\n    href: \"https://motos.coches.net/\",\n  },\n  {\n    label: \"Milanuncios\",\n    href: \"https://www.milanuncios.com/\",\n  },\n]\n---\n\n<div class=\"flex flex-col items-center px-10\">\n  <ul\n    class=\"hidden md:inline-flex gap-x-4 gap-y-4 flex-wrap justify-center text-sm w-full pb-10 underline-offset-[3px]\"\n  >\n    <li>\n      <span>InfoJobs es partner de </span>\n    </li>\n\n    {\n      LINKS.map(({ label, href }, index: number) => (\n        <li\n          class={`${index !== LINKS.length - 1 && \"after:content-['|'] after:ml-4\"} text-center`}\n        >\n          <a\n            class=\"hover:underline\"\n            href={href}\n            target=\"_blank\"\n            aria-label={`Visita ${label}`}\n          >\n            {label}\n          </a>\n        </li>\n      ))\n    }\n\n    <li class=\"text-center\">\n      <span>© 2024 Adevinta Jobs S.L.U.</span>\n    </li>\n  </ul>\n</div>\n"
  },
  {
    "path": "src/components/BentoInfo.astro",
    "content": "---\nimport SectionContainer from \"@components/SectionContainer.astro\"\nimport Subtitle from \"@components/Subtitle.astro\"\n\nconst ARTICLES = [\n  {\n    title: \"Qué esperar de un proceso de selección\",\n    contentId: \"selection-process\",\n    class:\n      \"bg-gradient-to-r from-[#fef6db] to-[#fce197] text-ij-yellow md:aspect-[16/8] md:col-span-2 md:row-span-1 h-full\",\n    image: \"/bento-info/selection-process.webp\",\n    imageClass:\n      \"w-full h-auto object-contain object-bottom md:h-auto md:w-auto md:object-right md:max-h-none\",\n    action: \"modal\",\n    track: \"blog_selection_process\",\n  },\n  {\n    title: \"Los puestos emergentes que van a petarlo\",\n    contentId: \"emergent-positions\",\n    class:\n      \"bg-gradient-to-r from-[#ffd2d2] to-[#f9b395] text-ij-red md:col-start-3 md:row-span-2 md:h-full\",\n    image: \"/bento-info/emergent-positions.webp\",\n    imageClass:\n      \"w-full h-full object-cover object-[center_30%] md:object-center\",\n    action: \"modal\",\n    track: \"blog_emerging_jobs\",\n  },\n  {\n    title: \"Las opinión de las empresas\",\n    contentId: \"company-opinion\",\n    class: \"bg-sky-800 text-ij-blue md:h-row-span-1\",\n    image: \"/bento-info/company-opinion.webp\",\n    imageClass: \"w-full h-full object-cover\",\n    action: \"link\",\n    link: \"https://www.tiktok.com/@infojobs/video/7291016517217520928?_r=1&amp%3B_t=8oUBsz4let7\",\n    track: \"blog_companies_opinions\",\n  },\n  {\n    title: \"¿Sin experiencia? Destaca en las entrevistas\",\n    contentId: \"no-experience\",\n    class:\n      \"bg-gradient-to-r from-[#e6f6ee] to-[#8bcfad] text-ij-green md:h-row-span-1 md:h-full\",\n    image: \"/bento-info/no-experience.webp\",\n    imageClass: \"w-3/4 h-auto object-contain mb-4\",\n    action: \"modal\",\n    track: \"blog_interview_tips\",\n  },\n]\n---\n\n<SectionContainer>\n  <Subtitle>Prepárate para ganar</Subtitle>\n  <div class=\"grid grid-cols-1 md:grid-cols-3 md:grid-rows-2 gap-4 md:p-0\">\n    {\n      ARTICLES.map(\n        ({\n          class: className,\n          title,\n          contentId,\n          image,\n          imageClass,\n          action,\n          link,\n          track,\n        }) =>\n          action === \"link\" ? (\n            <a\n              href={link}\n              target=\"_blank\"\n              class:list={[\n                \"aspect-square w-full h-full rounded-2xl overflow-hidden relative group\",\n                className,\n              ]}\n              data-track={track}\n            >\n              <div\n                class:list={[\n                  \"absolute inset-0 flex overflow-hidden p-0\",\n                  \"items-end justify-end\",\n                ]}\n              >\n                <img\n                  src={image}\n                  alt=\"\"\n                  class:list={[\n                    \"transition-transform duration-300 ease-in-out group-hover:scale-110\",\n                    imageClass,\n                  ]}\n                />\n              </div>\n              <div class=\"absolute inset-0 p-4 flex flex-col justify-start items-start z-10\">\n                <span class=\"font-medium text-3xl text-left text-pretty tracking-separated pr-3 md:max-w-64\">\n                  {title}\n                </span>\n              </div>\n            </a>\n          ) : (\n            <button\n              class:list={[\n                \"aspect-square w-full h-full rounded-2xl overflow-hidden relative group\",\n                className,\n              ]}\n              data-content-id={contentId}\n              data-track={track}\n            >\n              <div\n                class:list={[\n                  \"absolute inset-0 flex overflow-hidden p-0\",\n                  contentId === \"selection-process\"\n                    ? \"items-end justify-center md:items-stretch md:justify-end\"\n                    : \"\",\n                  contentId === \"emergent-positions\"\n                    ? \"items-start md:items-center\"\n                    : \"\",\n                  contentId === \"no-experience\"\n                    ? \"items-end justify-center\"\n                    : \"items-end justify-end\",\n                ]}\n              >\n                <img\n                  src={image}\n                  alt=\"\"\n                  class:list={[\n                    \"transition-transform duration-300 ease-in-out group-hover:scale-110\",\n                    imageClass,\n                    contentId === \"selection-process\"\n                      ? \"max-h-[70%] md:max-h-none md:h-full md:w-auto md:pr-0\"\n                      : \"\",\n                  ]}\n                />\n              </div>\n              <div class=\"absolute inset-0 p-4 flex flex-col justify-start items-start z-10\">\n                <span class=\"font-medium text-3xl text-left text-pretty tracking-separated pr-3 md:max-w-64\">\n                  {title}\n                </span>\n              </div>\n            </button>\n          )\n      )\n    }\n  </div>\n</SectionContainer>\n\n<script>\n  document.addEventListener(\"DOMContentLoaded\", () => {\n    // modal\n    const $modal = document.getElementById(\"infographic-modal\")\n    const $modalBody = document.getElementById(\"infographic-modal-body\")\n    const $btnModal = document.getElementById(\"btn-modal\")\n    const $body = document.body\n\n    // buttons bento\n    const $buttons = document.querySelectorAll(\"button[data-content-id]\")\n\n    const openModal = (id: string) => {\n      const contentId = `infographic-${id}`\n      const content = document.getElementById(contentId)\n\n      if (content && $modalBody) {\n        $modal?.classList.add(\"modal-active\")\n        $modalBody.replaceChildren(content.cloneNode(true))\n\n        $modalBody.firstElementChild?.classList.replace(\"hidden\", \"flex\")\n\n        $body.style.overflow = \"hidden\"\n      }\n    }\n\n    const closeModal = () => {\n      if ($modal?.classList.contains(\"modal-active\")) {\n        $modal?.classList.remove(\"modal-active\")\n      }\n\n      const currentContent = $modalBody?.firstChild\n\n      if (currentContent) {\n        $modalBody?.removeChild(currentContent)\n      }\n\n      $body.style.overflow = \"\"\n    }\n\n    const handleKeyDown = (event: KeyboardEvent) => {\n      if (event.key === \"Escape\") {\n        closeModal()\n      }\n    }\n\n    $buttons.forEach((button) => {\n      button.addEventListener(\"click\", () => {\n        const id = button.getAttribute(\"data-content-id\")\n        if (id) openModal(id)\n      })\n    })\n\n    $btnModal?.addEventListener(\"click\", () => closeModal())\n    document.addEventListener(\"keydown\", handleKeyDown)\n  })\n</script>\n"
  },
  {
    "path": "src/components/CoolJobBackground.astro",
    "content": "<img\n  src=\"/img/cool-jobs/pattern.webp\"\n  alt=\"Cool Jobs Background Pattern\"\n  class=\"hidden lg:block lg:absolute lg:top-16 lg:right-2\"\n/>\n"
  },
  {
    "path": "src/components/CoolJobBrand.astro",
    "content": "<a\n  href=\"https://cooljobs.infojobs.net/\"\n  target=\"_blank\"\n  rel=\"noopener noreferrer\"\n  data-track=\"cool_jobs\"\n  class:list={[\n    \"group transition hover:bg-[#fe5230] bg-[#fe52308f] h-24 max-w-[312px] rounded-2xl gap-4 lg:flex-col lg:items-start lg:justify-center m-auto\",\n    Astro.props.class,\n  ]}\n>\n  <div class=\"flex flex-col justify-center items-center p-6 gap-1\">\n    <img\n      src=\"/img/cool-jobs/cool-jobs.webp\"\n      alt=\"Logo Cool Jobs\"\n      class=\"px-0 group-hover:scale-105 transition-transform\"\n    />\n    <p\n      class=\"text-white text-sm p-0 text-center md:pl-1 md:text-start md:w-full\"\n    >\n      {\"Ver todos >\"}\n    </p>\n  </div>\n</a>\n"
  },
  {
    "path": "src/components/CoolJobCard.astro",
    "content": "---\nconst { image, brand, title, id } = Astro.props\n---\n\n<a\n  href=`https://cooljobs.infojobs.net/#${id}`\n  target=\"_blank\"\n  data-track=\"cool_jobs\"\n>\n  <article\n    class=\"flex items-center p-4 group min-w-[274px] md:p-6 md:max-w-[312px] h-24 rounded-2xl border border-[#FE523052] overflow-hidden bg-white snap-center\"\n  >\n    <div\n      class=\"flex items-center justify-center gap-4 transition-transform group-hover:scale-105\"\n    >\n      <div class=\"flex items-center h-10\">\n        <img src={image} alt={brand} class=\"w-20 h-auto\" loading=\"lazy\" />\n      </div>\n      <p class=\"font-medium md:font-semibold\">\n        {title}\n      </p>\n    </div>\n  </article>\n</a>\n"
  },
  {
    "path": "src/components/CoolJobs.astro",
    "content": "---\nimport CoolJobCard from \"@components/CoolJobCard.astro\"\nimport type { CoolJobs } from \"@types\"\nimport CoolJobBackground from \"@components/CoolJobBackground.astro\"\nimport CoolJobBrand from \"@components/CoolJobBrand.astro\"\n\nconst coolJobs: CoolJobs[] = [\n  {\n    image: \"/img/cool-jobs/port-aventura.webp\",\n    title: \"Probador de montañas rusas\",\n    brand: \"Port Aventura World\",\n    section_id: \"lp-pom-box-499\",\n  },\n  {\n    image: \"/img/cool-jobs/maxibon.webp\",\n    title: \"Catadora de helados\",\n    brand: \"Maxibon\",\n    section_id: \"lp-pom-box-515\",\n  },\n  {\n    image: \"/img/cool-jobs/wizink-center.webp\",\n    title: \"Probadora de conciertos\",\n    brand: \"WiZink Center\",\n    section_id: \"lp-pom-box-528\",\n  },\n  {\n    image: \"/img/cool-jobs/dominos.webp\",\n    title: \"Catadora de pizzas\",\n    brand: \"Domino's\",\n    section_id: \"lp-pom-box-534\",\n  },\n  {\n    image: \"/img/cool-jobs/btravel.webp\",\n    title: \"Probadora de viajes\",\n    brand: \"B travel\",\n    section_id: \"lp-pom-box-584\",\n  },\n  {\n    image: \"/img/cool-jobs/grefusa.webp\",\n    title: \"Probadora de snacks\",\n    brand: \"Grefusa\",\n    section_id: \"lp-pom-box-522\",\n  },\n  {\n    image: \"/img/cool-jobs/visa.webp\",\n    title: \"Probador de pagos con el móvil\",\n    brand: \"Visa\",\n    section_id: \"lp-pom-box-598\",\n  },\n]\n---\n\n<section class=\"w-full mx-auto lg:max-w-7xl\">\n  <article\n    class=\"p-4 pb-6 flex flex-col gap-6 bg-gradient-to-r from-[#FFDEDA] to-[#FCEDEB] md:py-[70px] md:px-10 md:items-center md:relative md:rounded-2xl md:mx-4\"\n  >\n    <CoolJobBackground />\n\n    <h2\n      class=\"text-3xl font-semibold text-center text-ij-red tracking-separated lg:text-4xl lg:z-10 lg:mb-4\"\n    >\n      Los trabajos más cool\n    </h2>\n\n    <div\n      class=\"flex items-center px-16 pb-6 -mx-4 overflow-x-auto no-scrollbar gap-7 snap-x snap-mandatory max-w-[1536px] md:overflow-visible md:grid md:grid-cols-2 lg:grid-cols-3 lg:p-0 lg:m-0 lg:z-10 md:justify-items-center xl:grid-cols-4\"\n    >\n      {\n        coolJobs.map(({ image, title, brand, section_id }) => (\n          <CoolJobCard\n            image={image}\n            title={title}\n            brand={brand}\n            id={section_id}\n          />\n        ))\n      }\n\n      <CoolJobBrand class=\"hidden md:flex\" />\n    </div>\n\n    <CoolJobBrand class=\"md:hidden min-w-[328px]\" />\n  </article>\n</section>\n"
  },
  {
    "path": "src/components/EmergentPositions.astro",
    "content": "---\nimport InfographicBody from \"./InfographicBody.astro\";\nimport InfographicHeader from \"./InfographicHeader.astro\";\n\nconst standsInterviewsBig = [\n  {\n    title: \"Inteligencia Artificial\",\n    description: \"Ingeniero/a de Machine Learning\",\n    requirements: [\n      {\n        label: \"📖 Estudios\",\n        tag: [\"Ciencia Computacional\", \"Matemáticas\", \"Estadística\"],\n      },\n      {\n        label: \"📝 Condiciones\",\n        tag: [\"Contrato indefinido\", \"Salario de 35k-58k €/año\"],\n      },\n      {\n        label: \"🦾 Hard Skills\",\n        tag: [\"Python\", \"R\", \"TensorFlow\", \"PyTorch\"],\n      },\n      {\n        label: \"👋 Soft Skills\",\n        tag: [\"Pensamiento critico\", \"Trabajo en equipo\", \"Analisis\"],\n      },\n    ],\n    location: [\n      {\n        label: \"📍 Dónde\",\n        tag1: \"Madrid\",\n        tag2: \"Barcelona\",\n      },\n    ],\n    image1:\n      \"bg-[url(/img/emergent-positions/madrid.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center \",\n    image2:\n      \"bg-[url(/img/emergent-positions/barcelona.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    backgroundColor:\n      \"bg-[url(/img/emergent-positions/bg2Img1.webp)] text-[#3C49F0] md:bg-cover md:bg-[url(/img/emergent-positions/bgImg1.webp)] \",\n    backgroundColor2: \"bg-[#CCCCFA]\",\n    backgroundColor3: \"bg-[#9B9DF6]\",\n  },\n  {\n    title: \"Data/Analytics\",\n    description: \"Data Engineer\",\n    requirements: [\n      {\n        label: \"📖 Estudios\",\n        tag: [\"Ingeniería informática\", \"Telecomunicaciones\"],\n      },\n      {\n        label: \"📝 Condiciones\",\n        tag: [\"Contrato indefinido\", \"Salario de 33k-60k €/año\"],\n      },\n      {\n        label: \"🦾 Hard Skills\",\n        tag: [\"SQL\", \"Python\", \"Big Data\", \"Spark\"],\n      },\n      {\n        label: \"👋 Soft Skills\",\n        tag: [\"Resolución de problemas\", \"Adaptación al cambio\"],\n      },\n    ],\n    location: [\n      {\n        label: \"📍 Dónde\",\n        tag1: \"Barcelona\",\n        tag2: \"Valencia\",\n      },\n    ],\n    image1:\n      \"bg-[url(/img/emergent-positions/barcelona.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    image2:\n      \"bg-[url(/img/emergent-positions/valencia.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    backgroundColor:\n      \"  text-[#008949] bg-[url(/img/emergent-positions/bg2Img2.webp)] md:bg-cover md:bg-[url(/img/emergent-positions/bgImg2.webp)] \",\n    backgroundColor2: \"bg-[#B4E5CD]\",\n    backgroundColor3: \"bg-[#3EB87E]\",\n  },\n  {\n    title: \" Building Information Modeling (BIM)\",\n    description: \"Arquitecto/a BIM\",\n    requirements: [\n      {\n        label: \"📖 Estudios\",\n        tag: [\"Arquitectura\", \"Ingeneiría de Edificación\"],\n      },\n      {\n        label: \"📝 Condiciones\",\n        tag: [\"Contrato indefinido\", \"Salario de 30k-50k €/año\"],\n      },\n      {\n        label: \"🦾 Hard Skills\",\n        tag: [\"Revit\", \"AutoCAD\", \"Gestión de proyectos\"],\n      },\n      {\n        label: \"👋 Soft Skills\",\n        tag: [\"Comunicación\", \"Liderazgo\", \"Autogestión\"],\n      },\n    ],\n    location: [\n      {\n        label: \"📍 Dónde\",\n        tag1: \"Barcelona\",\n        tag2: \"Sevilla\",\n      },\n    ],\n    image1:\n      \"bg-[url(/img/emergent-positions/barcelona.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    image2:\n      \"bg-[url(/img/emergent-positions/sevilla.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    backgroundColor:\n      \" text-[#D1A22E] bg-[url(/img/emergent-positions/bg2Img3.webp)] md:bg-cover md:bg-[url(/img/emergent-positions/bgImg3.webp)]\",\n    backgroundColor2: \"bg-[#FDECBE]\",\n    backgroundColor3: \"bg-[#F7CE5B] text-xs md:text-[0.7rem]\",\n  },\n  {\n    title: \" Ciberseguridad / Cloud\",\n    description: \"Cloud Security Engineer\",\n    requirements: [\n      {\n        label: \"📖 Estudios\",\n        tag: [\"Informática\", \"Ingeneiría en telecomunicaciones\"],\n      },\n      {\n        label: \"📝 Condiciones\",\n        tag: [\"Contrato indefinido\", \"Salario de 40k-60k €/año\"],\n      },\n      {\n        label: \"🦾 Hard Skills\",\n        tag: [\"AWS\", \"Azure\", \"Seguridad en la nube\"],\n      },\n      {\n        label: \"👋 Soft Skills\",\n        tag: [\"Atención al detalle\", \"Pensamiento analítico\"],\n      },\n    ],\n    location: [\n      {\n        label: \"📍 Dónde\",\n        tag1: \"Madrid\",\n        tag2: \"Málaga\",\n      },\n    ],\n    image1:\n      \"bg-[url(/img/emergent-positions/madrid.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    image2:\n      \"bg-[url(/img/emergent-positions/malaga.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    backgroundColor:\n      \"bg-[url(/img/emergent-positions/bg2Img4.webp)] md:bg-cover md:bg-[url(/img/emergent-positions/bgImg4.webp)] text-[#006895]\",\n    backgroundColor2: \"bg-[#C4DFEB]\",\n    backgroundColor3: \"bg-[#7BB6D3] text-xs\",\n  },\n  {\n    title: \"Quality Assurance (QA)\",\n    description: \"QA Automation Engineer\",\n    requirements: [\n      {\n        label: \"📖 Estudios\",\n        tag: [\"Ingeneiría Técnica o Superior \"],\n      },\n      {\n        label: \"📝 Condiciones\",\n        tag: [\"Contrato indefinido\", \"Salario de 30k-50k €/año\"],\n      },\n      {\n        label: \"🦾 Hard Skills\",\n        tag: [\"Selenium\", \"Jenkins\", \"Python\"],\n      },\n      {\n        label: \"👋 Soft Skills\",\n        tag: [\"Proactividad\", \"Resolución de problemas\"],\n      },\n    ],\n    location: [\n      {\n        label: \"📍 Dónde\",\n        tag1: \"Madrid\",\n        tag2: \"Bilbao\",\n      },\n    ],\n    image1:\n      \"bg-[url(/img/emergent-positions/madrid.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    image2:\n      \"bg-[url(/img/emergent-positions/bilbao.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    backgroundColor:\n      \"bg-[url(/img/emergent-positions/bg2Img5.webp)] md:bg-cover md:bg-[url(/img/emergent-positions/bgImg5.webp)] text-[#DF4D3A]\",\n    backgroundColor2: \"bg-[#FAC7C8]\",\n    backgroundColor3: \"bg-[#F1696E] text-xs\",\n  },\n  {\n    title: \"Eficiencia Energética\",\n    description: \"Ingeniero/a de Eficiencia Energética\",\n    requirements: [\n      {\n        label: \"📖 Estudios\",\n        tag: [\"Ingeniero/a de Eficiencia Energética\"],\n      },\n      {\n        label: \"📝 Condiciones\",\n        tag: [\"Contrato indefinido\", \"Salario de 30k-50k €/año\"],\n      },\n      {\n        label: \"🦾 Hard Skills\",\n        tag: [\"Presto\", \"DIALux\", \"Análisis de costes\"],\n      },\n      {\n        label: \"👋 Soft Skills\",\n        tag: [\"Organización\", \"Planificación\"],\n      },\n    ],\n    location: [\n      {\n        label: \"📍 Dónde\",\n        tag1: \"Valencia\",\n        tag2: \"Zaragoza\",\n      },\n    ],\n    image1:\n      \"bg-[url(/img/emergent-positions/valencia.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    image2:\n      \"bg-[url(/img/emergent-positions/zaragoza.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    backgroundColor:\n      \"bg-[url(/img/emergent-positions/bg2Img6.webp)] md:bg-cover md:bg-[url(/img/emergent-positions/bgImg6.webp)] text-[#009B4E]  \",\n    backgroundColor2: \"bg-[#B4E5CD]\",\n    backgroundColor3: \"bg-[#008949] md:text-[0.6rem]\",\n  },\n  {\n    title: \"Vocación social\",\n    description: \"Psicólogo/a\",\n    requirements: [\n      {\n        label: \"📖 Estudios\",\n        tag: [\"Psicología\", \"Trabajo Social\"],\n      },\n      {\n        label: \"📝 Condiciones\",\n        tag: [\"Contrato indefinido\", \"Salario de 12k-24k €/año\"],\n      },\n      {\n        label: \"🦾 Hard Skills\",\n        tag: [\"Intervención psicológica\", \"Programas sociales\"],\n      },\n      {\n        label: \"👋 Soft Skills\",\n        tag: [\"Empatía\", \"Paciencia\", \"Comunicación asertiva\"],\n      },\n    ],\n    location: [\n      {\n        label: \"📍 Dónde\",\n        tag1: \"Madrid\",\n        tag2: \"Valencia\",\n      },\n    ],\n    image1:\n      \"bg-[url(/img/emergent-positions/madrid.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    image2:\n      \"bg-[url(/img/emergent-positions/valencia.webp)] w-[31.25rem] md:h-[11rem] h-[7rem] bg-cover bg-center\",\n    backgroundColor:\n      \"bg-[url(/img/emergent-positions/bg2Img7.webp)] md:bg-cover md:bg-[url(/img/emergent-positions/bgImg7.webp)] text-[#006895]\",\n    backgroundColor2: \"bg-[#C4DFEB]\",\n    backgroundColor3: \"bg-[#7BB6D3] md:text-[0.6rem]\",\n  },\n  // Agrega más objetos según sea necesario\n];\n\nconst { infographicId } = Astro.props;\n---\n\n<section\n  id={`infographic-${infographicId}`}\n  class=\"mx-auto px-4 max-w-7xl w-full flex-col md:gap-[50px] py-[72px] hidden\"\n>\n  <InfographicHeader\n    badgeText=\"Puestos Emergentes\"\n    title=\"¿Quieres saber qué estudiar para lograr los trabajos del futuro?\"\n    subtitle=\"¡Te lo explicamos!\"\n  />\n\n  <InfographicBody bentoInfoModalCardsBig={standsInterviewsBig} />\n</section>\n"
  },
  {
    "path": "src/components/FollowUs.astro",
    "content": "---\nimport FollowUsLink from \"@components/FollowUsLink.astro\";\nimport Icon from \"./ui/Icon.astro\";\n\nconst hoverSocialNetworks = \"md:transition-transform md:hover:scale-110\";\nconst hoverStoreApps = \"md:transition-opacity md:duration-150 md:ease-in-out md:hover:opacity-90\";\n---\n\n\n<section class=\"flex flex-col items-center justify-between md:flex-row md:p-10\">\n  <article\n    class=\"w-full flex items-center justify-center gap-2 py-4 flex-wrap md:justify-start\"\n  >\n    <p class=\"text-xl tracking-[0.38px] leading-6 font-semibold\">\n      ¡Síguenos!\n    </p>\n\n    <span class=\"flex items-center gap-2\">\n      <FollowUsLink\n        href=\"https://www.tiktok.com/@infojobs\"\n        class={hoverSocialNetworks}\n        socialPlatform=\"Visítanos en TikTok.\"\n      >\n        <Icon name=\"tiktok\" />\n      </FollowUsLink>\n\n      <FollowUsLink\n        href=\"https://www.youtube.com/InfoJobs\"\n        class={hoverSocialNetworks}\n        socialPlatform=\"Visítanos en YouTube.\"\n      >\n        <Icon name=\"youtube\" />\n      </FollowUsLink>\n\n      <FollowUsLink\n        href=\"https://x.com/InfoJobs\"\n        class={hoverSocialNetworks}\n        socialPlatform=\"Visítanos en X.\"\n      >\n        <Icon name=\"twitter\" />\n      </FollowUsLink>\n\n      <FollowUsLink\n        href=\"https://www.facebook.com/InfoJobs\"\n        class={hoverSocialNetworks}\n        socialPlatform=\"Visítanos en Facebook.\"\n      >\n        <Icon name=\"facebook\" />\n      </FollowUsLink>\n    </span>\n  </article>\n\n  <article\n    class=\"w-full flex items-center justify-center gap-4 py-4 flex-wrap md:flex-nowrap md:p-0 md:gap-2 md:justify-end\"\n  >\n    <FollowUsLink\n      href=\"https://infojobs.go.link/?adj_t=1b8zxouv_1bnixj2z\"\n      class={hoverStoreApps}\n      socialPlatform=\"Visítanos en Google.\"\n    >\n     <Icon name=\"googleplay\" />\n    </FollowUsLink>\n\n    <FollowUsLink\n      href=\"https://infojobs.onelink.me/2882600328/rjh2wn2f\"\n      class={hoverStoreApps}\n      socialPlatform=\"Visítanos en la AppStore.\"\n    >\n      <Icon name=\"appstore\" />\n    </FollowUsLink>\n  </article>\n</section>\n"
  },
  {
    "path": "src/components/FollowUsLink.astro",
    "content": "---\nconst { href, socialPlatform } = Astro.props;\n---\n\n<a\n  href={href}\n  target=\"_blank\"\n  rel=\"noopener noreferrer\"\n  class={Astro.props.class}\n  aria-label={socialPlatform}\n>\n  <slot />\n</a>\n"
  },
  {
    "path": "src/components/Footer.astro",
    "content": "---\nimport LinksColumns from \"@components/LinksColumns.astro\"\nimport FollowUs from \"@components/FollowUs.astro\"\nimport AdevintaInfo from \"@components/AdevintaInfo.astro\"\n---\n\n<footer class=\"bg-[#F5F5F5] py-6 lg:py-10 mt-20\">\n  <section class=\"mx-auto max-w-7xl px-4 w-full\">\n    <LinksColumns />\n    <FollowUs />\n    <AdevintaInfo />\n  </section>\n</footer>\n"
  },
  {
    "path": "src/components/Header.astro",
    "content": "---\nimport Button from \"./ui/Button.astro\"\n---\n\n<header\n  id=\"header\"\n  class=\"py-4 px-8 flex justify-between items-center md:max-w-[1400px] md:mx-auto sticky top-0 right-0 left-0 bg-white/70 z-50 mb-4 backdrop-blur-xl\"\n>\n  <a href=\"#\" aria-label=\"Regresar a la página de inicio\"\n    ><img src=\"/logo.svg\" alt=\"Logo InfoJobs\" class=\"w-auto h-[30px]\" /></a\n  >\n\n  <Button\n    variant=\"solid\"\n    color=\"primary\"\n    size=\"lg\"\n    radius=\"full\"\n    as=\"link\"\n    href=\"https://www.infojobs.net/candidate/candidate-login/candidate-login.xhtml\"\n  >\n    Crea tu cuenta\n  </Button>\n</header>"
  },
  {
    "path": "src/components/HeroSearch.astro",
    "content": "---\nimport SearchIcon from \"@icons/Search.astro\"\nimport { getStudies } from \"@lib/get-ij-studies\"\nimport SectionContainer from \"@components/SectionContainer.astro\"\nimport Button from \"@ui/Button.astro\"\nimport ChevronDown from \"@icons/ChevronDown.astro\"\n\nconst SHORTCUTS = [\n  {\n    label: \"🌱  Sin experiencia\",\n    href: \"https://www.infojobs.net/jobsearch/search-results/list.xhtml?keyword=&segmentId=&page=1&sortBy=PUBLICATION_DATE&onlyForeignCountry=false&countryIds=17&sinceDate=ANY&experienceMin=_0_YEARS&experienceMax=_0_YEARS\",\n    track: \"explore_no_experience\",\n  },\n  {\n    label: \"🗓️  Findes\",\n    href: \"https://www.infojobs.net/ofertas-trabajo/fines-de-semana\",\n    track: \"explore_weekend_jobs\",\n  },\n  {\n    label: \"🕒  Media jornada\",\n    href: \"https://www.infojobs.net/ofertas-trabajo/media-jornada\",\n    track: \"explore_part_time\",\n  },\n  {\n    label: \"💼  Prácticas\",\n    href: \"https://www.infojobs.net/ofertas-trabajo/practicas\",\n    track: \"explore_internships\",\n  },\n] as const\n\nconst studies = await getStudies()\nconst sortedStudies = studies.sort((a, b) => a.order - b.order)\n---\n\n<SectionContainer>\n  <section\n    class=\"bg-hero-pattern rounded-3xl px-4 py-6 md:w-full md:max-w-7xl md:mx-auto\"\n  >\n    <h1\n      class=\"text-black/80 font-semibold tracking-[0.35px] text-2xl text-center pb-4 sm:text-4xl lg:hidden\"\n    >\n      Tu carrera empieza aquí\n    </h1>\n\n    <h1\n      class=\"hidden text-black/80 font-semibold tracking-[0.35px] text-2xl text-center pb-4 sm:text-4xl lg:pb-8 lg:block\"\n    >\n      Conecta tus estudios con el empleo ideal\n    </h1>\n\n    <search class=\"bg-white rounded-3xl p-4 lg:mx-10\">\n      <form\n        id=\"hero-form\"\n        class=\"mx-5 lg:flex lg:justify-between lg:items-center lg:gap-2\"\n      >\n        <div\n          id=\"study-level-container\"\n          class=\"flex items-center border-b border-gray-300 lg:border-none relative select-none outline-none lg:focus-visible:outline lg:focus-visible:outline-[#167DB7] lg:focus-visible:outline-1 lg:focus-visible:outline-offset-0 lg:focus-visible:rounded-lg rounded-md lg:w-full lg:px-4\"\n          tabindex=\"0\"\n          aria-haspopup=\"listbox\"\n          aria-expanded=\"false\"\n          aria-labelledby=\"study-level-container\"\n        >\n          <div\n            class=\"w-full py-4 text-gray-600 bg-transparent cursor-pointer flex justify-between items-center\"\n            aria-label=\"Selecciona tu nivel de estudios\"\n          >\n            <span id=\"study-level-text\"> Nivel de estudios </span>\n\n            <ChevronDown id=\"study-level-chevron\" width=\"24\" height=\"24\" />\n          </div>\n\n          <ul\n            id=\"study-level-options\"\n            role=\"listbox\"\n            class=\"absolute top-full mt-2 space-y-1 rounded-lg left-0 p-1 max-h-80 w-full border border-gray-300 bg-white shadow-md hidden overflow-auto no-scrollbar z-20\"\n            data-track=\"study_level\"\n          >\n            {\n              sortedStudies.map(({ id, value }) => {\n                const isDefault = id === 0\n                const literal = isDefault ? \"Nivel de estudios\" : value\n\n                return (\n                  <li\n                    id=\"study-level-option\"\n                    role=\"option\"\n                    class={`p-3 transition-colors duration-200 ease-in-out rounded-md outline-none cursor-pointer hover:bg-[#F3F9FB] focus-visible:bg-[#F3F9FB] ${isDefault ? \"text-gray-400 bg-none pointer-events-none\" : \"text-gray-600\"}`}\n                    data-value={id}\n                    aria-disabled={isDefault}\n                    aria-selected={isDefault}\n                    tabindex={isDefault ? -1 : 0}\n                  >\n                    {literal}\n                  </li>\n                )\n              })\n            }\n          </ul>\n        </div>\n\n        <div class=\"lg:w-full relative\">\n          <input\n            autocomplete=\"off\"\n            id=\"hero-keywords\"\n            name=\"keywords\"\n            placeholder=\"Estudios, puesto, empresa...\"\n            class=\"w-full py-3 lg:px-3 border-b border-gray-300 lg:border-none text-gray-600 focus:outline-none lg:focus-visible:bg-[#E8F2F8] lg:focus-visible:outline lg:focus-visible:outline-[#167DB7] lg:focus-visible:outline-1 lg:focus-visible:outline-offset-0 lg:focus-visible:rounded-lg\"\n            role=\"combobox\"\n            aria-expanded=\"false\"\n            aria-controls=\"hero-keywords-list\"\n            aria-autocomplete=\"list\"\n          />\n\n          <ul\n            id=\"hero-keywords-list\"\n            class=\"bg-white w-full mx-auto absolute inset-0 top-14 min-h-[224px] h-full max-h-[224px] z-[999] flex flex-col gap-1 p-1 rounded-lg border border-gray-300 shadow-md no-scrollbar [&>li]:rounded-md [&>li]:transition-colors [&>li]:duration-300 [&>li]:text-ij-black [&>li:hover]:bg-[#F3F9FB] [&>li]:p-3 [&>li]:cursor-pointer [&>li:focus]:bg-[#F3F9FB] [&>li:focus]:outline-none\"\n            role=\"listbox\"\n            aria-label=\"Lista de sugerencias\"\n            tabindex=\"0\"\n          >\n          </ul>\n        </div>\n\n        <div class=\"mb-8 lg:mb-0 lg:w-full\">\n          <input\n            name=\"geolocation\"\n            placeholder=\"Provincia o población\"\n            class=\"w-full py-3 lg:px-3 border-b border-gray-300 lg:border-none text-gray-600 focus:outline-none lg:focus-visible:bg-[#E8F2F8] lg:focus-visible:outline lg:focus-visible:outline-[#167DB7] lg:focus-visible:outline-1 lg:focus-visible:outline-offset-0 lg:focus-visible:rounded-lg\"\n          />\n        </div>\n        <Button\n          type=\"submit\"\n          color=\"secondary\"\n          variant=\"solid\"\n          size=\"md\"\n          radius=\"full\"\n          class=\"shadow-md rounded-full text-lg font-medium bg-accent hover:saturate-150 transition text-white px-4 py-2 inline-flex gap-x-2 justify-center items-center w-full lg:size-12 lg:mt-1 lg:hover:scale-105\"\n          ariaLabel=\"Buscar ofertas\"\n          track=\"job_search\"\n        >\n          <SearchIcon />\n          <p class=\"lg:hidden\">Buscar ofertas</p>\n        </Button>\n      </form>\n    </search>\n\n    <footer>\n      <p class=\"text-center pt-8 pb-4\">Explora trabajos que se adaptan a ti</p>\n      <div\n        class=\"max-xs:grid-cols-1 max-sm:grid max-sm:grid-cols-2 flex flex-wrap gap-4 justify-center\"\n      >\n        {\n          SHORTCUTS.map(({ label, href, track }) => (\n            <Button\n              as=\"link\"\n              href={href}\n              color=\"default\"\n              variant=\"solid\"\n              radius=\"full\"\n              size=\"lg\"\n              class=\"bg-white whitespace-nowrap text-center rounded-full p-4 lg:px-6 shadow-sm text-primary transition hover:scale-105 hover:text-white hover:bg-primary !font-light\"\n              disableSaturateHover={true}\n              track={track}\n            >\n              {label}\n            </Button>\n          ))\n        }\n      </div>\n    </footer>\n  </section>\n</SectionContainer>\n\n<script>\n  const select = document.querySelector(\"select\")\n\n  function updateColors() {\n    if (select?.value !== \"indicar-nivel\") {\n      select?.classList.add(\"text-gray-600\")\n    }\n  }\n\n  document.addEventListener(\"DOMContentLoaded\", updateColors)\n  select?.addEventListener(\"change\", updateColors)\n</script>\n\n<script>\n  import { generateInfoJobsURL } from \"@lib/generate-infojobs-url\"\n\n  const form = document.querySelector(\"#hero-form\") as HTMLFormElement\n\n  form?.addEventListener(\"submit\", (event) => {\n    event.preventDefault()\n    const formData = new FormData(form)\n    const level = formData.get(\"study-level\")?.toString() ?? \"\"\n    const keyword = formData.get(\"keywords\")?.toString() ?? \"\"\n    const provinceIds =\n      form.querySelector('input[name=\"geolocation\"]')?.getAttribute(\"value\") ??\n      \"\"\n\n    const searchURL = generateInfoJobsURL({\n      keyword,\n      level,\n      provinceIds,\n    })\n\n    window.location.href = searchURL\n  })\n</script>\n\n<script>\n  import { queryKeywords } from \"@lib/queryKeywords\"\n\n  const inputKeyword = document.querySelector(\n    \"#hero-keywords\"\n  ) as HTMLInputElement\n  const keywordsContainer = document.querySelector(\n    \"#hero-keywords-list\"\n  ) as HTMLUListElement\n\n  const renderedKeywords = new Set()\n\n  // debounce para retrasar el fetch hacia la API que devuelve las keywords.\n  const debounce = (func: Function, delay: number) => {\n    let timeoutId: ReturnType<typeof setTimeout>\n    return (...args: any[]) => {\n      clearTimeout(timeoutId)\n      timeoutId = setTimeout(() => func(...args), delay)\n    }\n  }\n\n  const debouncedFetchKeywords = debounce((value: string) => {\n    fetchKeywords(value)\n  }, 300)\n\n  inputKeyword?.addEventListener(\"input\", (event) => {\n    const value = (event.target as HTMLInputElement).value\n\n    if (value.length > 1) {\n      debouncedFetchKeywords(value)\n      openListElement()\n    } else {\n      closeListElement()\n    }\n  })\n\n  const fetchKeywords = async (value: string) => {\n    const keywordsList: [] = await queryKeywords(value)\n\n    keywordsContainer.innerHTML = \"\"\n    renderedKeywords.clear()\n\n    if (keywordsList.length > 0) {\n      keywordsList.forEach(({ value: queryValue }) => {\n        if (!renderedKeywords.has(queryValue)) {\n          renderedKeywords.add(queryValue)\n\n          const li = document.createElement(\"li\")\n          li.setAttribute(\"role\", \"option\")\n          li.tabIndex = 0\n          li.id = `keyword-${queryValue}`\n          li.innerHTML = getHighlightedKeyword(value, queryValue)\n\n          li.addEventListener(\"click\", () => {\n            inputKeyword.value = li.textContent!\n            closeListElement()\n          })\n\n          keywordsContainer.appendChild(li)\n        }\n      })\n\n      openListElement()\n    } else {\n      closeListElement()\n    }\n  }\n\n  const getHighlightedKeyword = (\n    inputValue: string,\n    queryValue: string\n  ): string => {\n    const regex = new RegExp(inputValue, \"gi\")\n    return queryValue.replace(\n      regex,\n      (match) => `<mark class=\"font-bold bg-transparent\">${match}</mark>`\n    )\n  }\n\n  const handleClickOutsideList = (event: any) => {\n    if (!event.target.matches(\"#hero-keywords-list *\")) {\n      closeListElement()\n    } else {\n      document.removeEventListener(\"click\", handleClickOutsideList)\n    }\n  }\n\n  const openListElement = () => {\n    keywordsContainer.classList.add(\"list-active\")\n    inputKeyword.ariaExpanded = \"true\"\n    document.addEventListener(\"keydown\", handleKeyPress)\n  }\n\n  const closeListElement = () => {\n    keywordsContainer.classList.remove(\"list-active\")\n    keywordsContainer.ariaExpanded = \"false\"\n    keywordsContainer.innerHTML = \"\"\n    renderedKeywords.clear()\n    document.removeEventListener(\"keydown\", handleKeyPress)\n  }\n\n  const handleKeyPress = (event: KeyboardEvent) => {\n    if (event.code === \"ArrowDown\" || event.code === \"ArrowUp\") {\n      event.preventDefault()\n      const activeElement = document.activeElement\n\n      if (activeElement?.tagName !== \"LI\") {\n        const firstElement =\n          keywordsContainer.firstElementChild as HTMLLIElement\n        firstElement.tabIndex = 0\n        firstElement.focus()\n        return\n      }\n\n      const nextElement =\n        event.code === \"ArrowDown\"\n          ? (activeElement.nextElementSibling as HTMLLIElement)\n          : (activeElement.previousElementSibling as HTMLLIElement)\n\n      if (nextElement) {\n        activeElement.setAttribute(\"tabindex\", \"-1\")\n        nextElement.setAttribute(\"tabindex\", \"0\")\n        nextElement.focus()\n      }\n    }\n\n    if (event.code === \"Enter\" || event.code === \"Space\") {\n      event.preventDefault()\n      const activeElement = document.activeElement\n\n      if (activeElement?.tagName === \"LI\") {\n        inputKeyword.value = activeElement.textContent!\n        closeListElement()\n      }\n    }\n\n    if (event.code === \"Escape\") {\n      event.preventDefault()\n      closeListElement()\n    }\n  }\n\n  document.addEventListener(\"click\", handleClickOutsideList)\n</script>\n\n<style>\n  #hero-keywords-list {\n    visibility: hidden;\n    opacity: 0;\n    overflow-y: scroll;\n    scrollbar-width: none;\n  }\n\n  #hero-keywords-list.list-active {\n    visibility: visible;\n    opacity: 1;\n  }\n</style>\n\n<script>\n  import { getProvinceId } from \"@lib/list-provinces-ids\"\n  const geolocationInput = document.querySelector(\n    'input[name=\"geolocation\"]'\n  ) as HTMLInputElement | null\n\n  geolocationInput?.addEventListener(\"input\", function () {\n    getProvinceId(this)\n  })\n</script>\n\n<script>\n  const $ = document.querySelector.bind(document)\n  const studyLevelContainer = $(\"#study-level-container\")\n  const studyLevelOptions = $(\"#study-level-options\") as HTMLUListElement\n  const studyLevelOption = $(\"#study-level-option\")\n  const studyLevelText = $(\"#study-level-text\")\n  const studyLevelChevron = $(\"#study-level-chevron\")\n  const hiddenSelect = document.createElement(\"input\")\n\n  hiddenSelect.type = \"hidden\"\n  hiddenSelect.name = \"study-level\"\n  studyLevelContainer?.appendChild(hiddenSelect)\n\n  studyLevelContainer?.addEventListener(\"click\", () => {\n    const isExpanded =\n      studyLevelContainer?.getAttribute(\"aria-expanded\") === \"true\"\n    studyLevelContainer?.setAttribute(\"aria-expanded\", `${!isExpanded}`)\n    studyLevelChevron?.classList.toggle(\"rotate-180\")\n    studyLevelOptions?.classList.toggle(\"hidden\")\n  })\n\n  document.addEventListener(\"click\", (event) => {\n    if (!studyLevelContainer?.contains(event.target as Node)) {\n      studyLevelContainer?.setAttribute(\"aria-expanded\", \"false\")\n      studyLevelChevron?.classList.remove(\"rotate-180\")\n      studyLevelOptions?.classList.add(\"hidden\")\n    }\n  })\n\n  studyLevelContainer?.addEventListener(\"keydown\", (evt) => {\n    const event = evt as KeyboardEvent\n\n    const isExpanded =\n      studyLevelContainer.getAttribute(\"aria-expanded\") === \"true\"\n\n    if (event.key === \"Enter\" || event.key === \" \") {\n      if (!isExpanded) {\n        studyLevelContainer.setAttribute(\"aria-expanded\", \"true\")\n        studyLevelChevron?.classList.toggle(\"rotate-180\")\n        studyLevelOptions?.classList.toggle(\"hidden\")\n        event.preventDefault()\n      } else {\n        const activeOption = document.activeElement as Element | null\n        const selectedOption = activeOption?.closest(\"[data-value]\")\n\n        if (\n          selectedOption &&\n          selectedOption.getAttribute(\"data-value\") !== \"0\"\n        ) {\n          const value = selectedOption.getAttribute(\"data-value\")\n          const text = selectedOption.textContent?.trim()\n\n          if (studyLevelText && hiddenSelect) {\n            studyLevelText.textContent = text as string\n            hiddenSelect.value = value as string\n          }\n\n          studyLevelOptions\n            ?.querySelectorAll(\"[data-value]\")\n            .forEach((option) => {\n              option.classList.remove(\"bg-[#F3F9FB]\")\n            })\n          selectedOption.classList.add(\"bg-[#F3F9FB]\")\n\n          studyLevelContainer?.setAttribute(\"aria-expanded\", \"false\")\n          studyLevelChevron?.classList.remove(\"rotate-180\")\n          studyLevelOptions?.classList.add(\"hidden\")\n\n          event.preventDefault()\n        }\n      }\n    }\n\n    if (isExpanded && (event.key === \"ArrowDown\" || event.key === \"ArrowUp\")) {\n      const options = studyLevelOptions?.querySelectorAll(\n        \"[data-value]\"\n      ) as NodeListOf<HTMLElement>\n      let index = Array.from(options).findIndex(\n        (option) => option === document.activeElement\n      )\n\n      if (event.key === \"ArrowDown\") index++\n      if (event.key === \"ArrowUp\") index--\n      if (index >= 0 && index < options.length) options[index]?.focus()\n\n      event.preventDefault()\n    }\n\n    if (isExpanded && event.key === \"Escape\") {\n      studyLevelContainer?.setAttribute(\"aria-expanded\", \"false\")\n      studyLevelChevron?.classList.remove(\"rotate-180\")\n      studyLevelOptions?.classList.add(\"hidden\")\n    }\n  })\n\n  studyLevelOptions?.addEventListener(\"click\", (event) => {\n    const target = event.target as Element | null\n    const selectedOption = target?.closest(\"[data-value]\")\n\n    if (selectedOption && selectedOption.getAttribute(\"data-value\") !== \"0\") {\n      const value = selectedOption.getAttribute(\"data-value\")\n      const text = selectedOption.textContent?.trim()\n\n      if (studyLevelText && hiddenSelect) {\n        studyLevelText.textContent = text as string\n        hiddenSelect.value = value as string\n      }\n\n      studyLevelOptions.querySelectorAll(\"[data-value]\").forEach((option) => {\n        option.classList.remove(\"bg-[#F3F9FB]\")\n      })\n      selectedOption.classList.add(\"bg-[#F3F9FB]\")\n    }\n  })\n\n  studyLevelOption?.addEventListener(\"click\", () => {\n    studyLevelContainer?.setAttribute(\"aria-expanded\", \"false\")\n    studyLevelChevron?.classList.remove(\"rotate-180\")\n    studyLevelOptions?.classList.add(\"hidden\")\n  })\n\n  studyLevelOptions?.addEventListener(\"wheel\", (evt) => {\n    const event = evt as WheelEvent\n    const { deltaY } = event\n    const { scrollTop, scrollHeight, offsetHeight } = studyLevelOptions\n\n    if (\n      (deltaY < 0 && scrollTop === 0) ||\n      (deltaY > 0 && scrollTop + offsetHeight >= scrollHeight)\n    ) {\n      event.preventDefault()\n    }\n  })\n</script>\n"
  },
  {
    "path": "src/components/InfographicBody.astro",
    "content": "---\ntype Props = {\n  bentoInfoModalCards?: readonly BentoInfoModalCard[]; // Ahora es opcional\n  bentoInfoModalCardsBig?: BentoInfoModalCardBig[];\n};\n\ntype BentoInfoModalCard = {\n  image: string;\n  title: string;\n  description: string;\n  firstBgColor: string;\n  secondBgColor: string;\n  textColor: string;\n};\n\ntype BentoInfoModalCardBig = {\n  title: string;\n  description: string;\n  requirements: { label: string; tag: string[] }[];\n  location: { label: string; tag1: string; tag2: string }[];\n  image1: string;\n  image2: string;\n  backgroundColor: string;\n  backgroundColor2: string;\n  backgroundColor3: string;\n};\n\nconst { bentoInfoModalCards = [], bentoInfoModalCardsBig = [] } =\n  Astro.props as Props;\n---\n\n<section\n  class='grid gap-[48px] md:justify-between grid-cols-1 lg:grid-cols-2 overflow-hidden'\n>\n  {\n    bentoInfoModalCards.map(\n      ({\n        image,\n        title,\n        description,\n        firstBgColor,\n        secondBgColor,\n        textColor,\n      }) => (\n        <article\n          class='file-card w-auto h-full mx-auto max-h-[456px] max-w-[330px] md:max-w-[600px] md:max-h-[630px] lg:min-h-[700px]'\n          style={{\n            background: `linear-gradient(to bottom right, ${firstBgColor}, ${secondBgColor})`,\n          }}\n        >\n          <div class='w-full h-full p-2 my-7'>\n            <img\n              src={image}\n              alt={`${title} Card`}\n              class='min-h-[115px] max-h-[115px] lg:min-h-[210px] lg:max-h-[210px] w-auto mx-auto my-7'\n            />\n\n            <div class='py-10 px-15 flex flex-col gap-6 items-center'>\n              <h4\n                class='text-[26px] leading-[26px] md:text-5xl md:leading-[48px] text-center'\n                style={{ color: textColor }}\n              >\n                {title}\n              </h4>\n\n              <p\n                class='text-[15px] leading-[15px] md:text-[28px] md:leading-7 text-center'\n                style={{ color: textColor }}\n              >\n                {description}\n              </p>\n            </div>\n          </div>\n        </article>\n      )\n    )\n  }\n</section>\n\n<section class='w-auto h-auto'>\n  {\n    bentoInfoModalCardsBig.map((card) => (\n      <article\n        class={`${card.backgroundColor} p-5 mb-20 rounded-3xl `}\n        style='background-size: 100% 100%;'\n      >\n        <h5\n          class={` ${card.backgroundColor3} uppercase py-2 px-4 w-fit  md:w-fit rounded-lg text-white text-sm lg:text-xl md:text-xs leading-5 text-center tracking-[2%] `}\n        >\n          {card.title}\n        </h5>\n        <p class=' lg:text-[3.5rem] lg:my-9 text-2xl my-3'>\n          {card.description}\n        </p>\n\n        <div class='grid grid-cols-1 md:grid-cols-2 sm:grid-cols-2 gap-6 mb-6'>\n          {card.requirements.map((requirement) => (\n            <div\n              class={`flex flex-col gap-3 ${card.backgroundColor2} rounded-[1.25rem] px-5 py-5 `}\n            >\n              <h6 class='rounded-xl text-base md:text-2xl bg-white text-black w-fit py-2 px-3'>\n                {requirement.label}\n              </h6>\n              <div class=' flex flex-wrap gap-2 md:gap-5 mt-2'>\n                {requirement.tag.map((tag) => (\n                  <span class='text-black sm:text-base md:text-2xl lg:text-3xl px-5 py-1 rounded-[2rem] border-[1px] border-[#5B666C80]  w-auto'>\n                    {tag}\n                  </span>\n                ))}\n              </div>\n            </div>\n          ))}\n        </div>\n\n        <div>\n          {card.location.map((location) => (\n            <div\n              class={`flex flex-col gap-2 justify-between ${card.backgroundColor2} rounded-[20px] px-5 py-6 `}\n            >\n              <h6 class='rounded-xl text-base md:text-2xl bg-white text-black w-fit py-2 px-3'>\n                {location.label}\n              </h6>\n              <div class='flex flex-col md:flex-row justify-around gap-2 mt-2'>\n                <div\n                  class={`rounded-xl ${card.image1} pl-4 pt-2 w-auto md:w-[48%]`}\n                >\n                  <span class='text-black text-base md:text-xl  w-full uppercase'>\n                    {location.tag1}\n                  </span>\n                </div>\n                <div\n                  class={`rounded-xl ${card.image2} pl-4 p-2 w-auto md:w-[48%] `}\n                >\n                  <span class='text-black text-base md:text-xl w-full uppercase'>\n                    {location.tag2}\n                  </span>\n                </div>\n              </div>\n            </div>\n          ))}\n        </div>\n      </article>\n    ))\n  }\n</section>\n\n<style>\n  .file-card {\n    border-radius: 2rem;\n    clip-path: polygon(\n      0% 0%,\n      calc(100% - 116.6px) 0.3px,\n      calc(100% - 112px) 1.2px,\n      calc(100% - 107.5px) 2.7px,\n      calc(100% - 103.4px) 4.8px,\n      calc(100% - 99.6px) 7.6px,\n      calc(100% - 7.2px) 102.1px,\n      calc(100% - 4.4px) 105.9px,\n      calc(100% - 2.3px) 110.1px,\n      calc(100% - 0.8px) 114.5px,\n      100% 121.5px,\n      100% 100%,\n      0% 100%\n    );\n  }\n</style>\n"
  },
  {
    "path": "src/components/InfographicHeader.astro",
    "content": "---\nconst { badgeText, title, subtitle } = Astro.props\n---\n\n<div class=\"flex flex-col gap-[10px] md:gap-[35px]\">\n  <span\n    class=\"uppercase bg-[#499AC3] py-2 px-4 w-full md:w-fit rounded-lg text-white text-xl leading-5 text-center tracking-[2%]\"\n  >\n    {badgeText}\n  </span>\n\n  <div class=\"py-10 flex flex-col gap-6\">\n    <h2\n      class=\"text-[32px] leading-[35.2px] md:text-[64px] md:leading-[70px] text-[#0073AA] max-w-5xl\"\n    >\n      {title}\n    </h2>\n\n    <h4 class=\"text-3xl leading-[30px] text-[#499AC3]\">{subtitle}</h4>\n  </div>\n</div>\n"
  },
  {
    "path": "src/components/InfographicModal.astro",
    "content": "---\nimport CloseIcon from \"@icons/CloseIcon.astro\";\n---\n\n<section\n  id=\"infographic-modal\"\n  class=\"transition-all fixed inset-0 bg-white py-2 z-[999] opacity-0 invisible\"\n>\n  <header class=\"w-full h-[40px] flex items-center justify-end px-4 lg:px-8\">\n    <button\n      id=\"btn-modal\"\n      class=\"p-2 rounded-full transition-colors md:hover:bg-gray-200\"\n    >\n      <CloseIcon />\n    </button>\n  </header>\n  <div\n    id=\"infographic-modal-body\"\n    class=\"h-full w-full rounded-lg overflow-y-auto\"\n  >\n  </div>\n</section>\n\n<style>\n  .modal-active {\n    opacity: 1;\n    visibility: visible;\n  }\n</style>\n"
  },
  {
    "path": "src/components/InfographicTips.astro",
    "content": "---\nconst TIPS = [\n  {\n    title: \"Favoritos\",\n    description: \"Marca como favoritas las empresas que te molen\",\n    image: \"/img/bento-info-modal-cards/heart-on-fire.webp\",\n    firstBgColor: \"#FFB3B6\",\n    secondBgColor: \"#FCD3D3\",\n    titleColor: \"#EA2E39\",\n    descriptionColor: \"#F1696E\",\n  },\n  {\n    title: \"Notificaciones\",\n    description: \"¡Recibirás un aviso cuando publiquen una oferta!\",\n    image: \"/img/bento-info-modal-cards/bell.webp\",\n    firstBgColor: \"#FFB3B6\",\n    secondBgColor: \"#FCD3D3\",\n    titleColor: \"#EA2E39\",\n    descriptionColor: \"#F1696E\",\n  },\n  {\n    title: \"Revisa tu CV\",\n    description:\n      \"Y tómate tu tiempo para contestar bien a las preguntas que hacen \",\n    image: \"/img/bento-info-modal-cards/eyes.webp\",\n    firstBgColor: \"#FFB3B6\",\n    secondBgColor: \"#FCD3D3\",\n    titleColor: \"#EA2E39\",\n    descriptionColor: \"#F1696E\",\n  },\n] as const;\n---\n\n<section class=\"relative mt-8 md:mt-0\">\n  <img\n    class=\"absolute top-0 left-1/2 -translate-x-1/2 h-auto w-8 xs:w-10 sm:w-14 md:w-16 lg:w-20 xl:w-24 z-10\"\n    src=\"/img/bento-info-modal-cards/fire.webp\"\n    alt=\"Icono de fuego\"\n  />\n\n  <div class=\"folder-shape rounded-lg md:rounded-2xl lg:rounded-3xl w-full h-full bg-[#FDE8E8]\">\n    <h3\n      class=\"pt-8 xs:pt-10 sm:pt-10 md:pt-14 lg:pt-20 xl:pt-24 text-center text-[#EA2E39] text-xl xs:text-2xl sm:text-3xl md:text-4xl lg:text-5xl xl:text-6xl\"\n    >\n      Trucos para petarlo\n    </h3>\n    <div\n      class=\"grid grid-cols-3 gap-2 xs:gap-4 md:gap-6 xl:gap-8 p-2 xs:p-4 md:p-6 xl:p-8\"\n    >\n      {\n        TIPS.map(\n          ({\n            image,\n            title,\n            description,\n            firstBgColor,\n            secondBgColor,\n            titleColor,\n            descriptionColor,\n          }) => (\n            <article\n              class=\"file-card rounded-lg md:rounded-2xl w-full h-full p-2 md:p-4 lg:p-8 bg-[#FFB3B6] flex flex-col items-center justify-center\"\n              style={{\n                background: `linear-gradient(to bottom right, ${firstBgColor} 0%, ${secondBgColor} 100%)`,\n              }}\n            >\n              <img\n                src={image}\n                alt={`${title} Card`}\n                class=\"pb-1 md:pb-4 h-auto w-8 xs:w-10 sm:w-14 md:w-16 lg:w-20 xl:w-24\"\n              />\n              <h4\n                class=\"text-xs xs:text-base sm:text-lg md:text-xl lg:text-2xl xl:text-3xl\"\n                style={{ color: titleColor }}\n              >\n                {title}\n              </h4>\n              <p\n                class=\"text-xs xs:text-sm sm:text-base md:text-lg lg:text-xl xl:text-2xl text-center py-2\"\n                style={{ color: descriptionColor }}\n              >\n                {description}\n              </p>\n            </article>\n          ),\n        )\n      }\n    </div>\n  </div>\n</section>\n\n<style>\n  /* prettier-ignore */\n  .folder-shape {\n    clip-path: polygon(0% 0%,26.37% 0%,26.55% 0.01%,27.07% 0.22%,27.55% 0.65%,27.98% 1.3%,30.54% 6.21%,30.96% 6.86%,31.28% 7.17%,31.79% 7.46%,32.14% 7.51%,97.64% 7.51%,98.38% 7.75%,98.72% 8.04%,99.03% 8.43%,99.53% 9.47%,99.87% 10.78%,99.99% 12.29%,100% 100%,0% 100%);\n  }\n\n  /* prettier-ignore */\n  .file-card {\n    clip-path: polygon(0% 0%,81.66% 0.03%,83.02% 0.19%,84.29% 0.66%,85.76% 1.72%,97.84% 13.61%,98.71% 14.70%,99.57% 17.31%,100% 100%,0% 100%);\n  }\n</style>\n"
  },
  {
    "path": "src/components/KingsLeagueInfo.astro",
    "content": "<div\n  class=\"w-full aspect-[9/16] sm:aspect-[16/9] sm:col-span-2 rounded-3xl overflow-hidden\"\n>\n  <div class=\"w-full h-full relative\">\n    <a\n      href=\"https://kingsleague.ofertas-trabajo.infojobs.net/\"\n      target=\"_blank\"\n      class=\"absolute inset-0 group\"\n      data-track=\"kings_league\"\n    >\n      <img\n        src=\"/img/kings-league/background.webp\"\n        alt=\"Kings League InfoJobs Background\"\n        class=\"w-full h-full object-cover object-[center_top]\"\n      />\n      <img\n        src=\"/img/kings-league/players.webp\"\n        alt=\"Kings League InfoJobs Players\"\n        class=\"absolute bottom-0 h-full w-full md:w-fit md:h-fit object-cover object-[center_top] transition-transform duration-700 ease-in-out group-hover:scale-110 md:scale-100\"\n      />\n      <div\n        class=\"absolute inset-0 p-4 sm:p-6 flex flex-col justify-start items-start z-10\"\n      >\n        <h3 class=\"text-2xl sm:text-2xl text-white/80\">Patrocinador oficial</h3>\n        <h2 class=\"text-5xl sm:text-5xl font-bold text-white\">\n          Kings League InfoJobs\n        </h2>\n      </div>\n    </a>\n  </div>\n</div>\n"
  },
  {
    "path": "src/components/LinksColumns.astro",
    "content": "---\nconst linksInfo = [\n  {\n    title: \"Nosotros\",\n    links: [\n      {\n        label: \"Ayuda\",\n        href: \"https://ayuda.infojobs.net/hc/es\",\n        showOnMobile: true,\n      },\n      {\n        label: \"Seguridad\",\n        href: \"https://nosotros.infojobs.net/infojobs-seguridad\",\n      },\n      {\n        label: \"Condiciones legales\",\n        href: \"https://www.infojobs.net/lex.xhtml\",\n        showOnMobile: true,\n      },\n      {\n        label: \"Política de privacidad\",\n        href: \"https://www.infojobs.net/privacy-policy/extended.xhtml\",\n      },\n\n      {\n        label: \"Uso del servicio\",\n        href: \"https://www.infojobs.net/rules-and-services.xhtml\",\n      },\n      {\n        label: \"Política de cookies\",\n        href: \"https://www.infojobs.net/lex.xhtml#cookies-policy\",\n      },\n      {\n        label: \"Gestión de cookies\",\n        href: \"https://www.figma.com/exit?url=javascript%3Avoid(null)%3B\",\n      },\n    ],\n  },\n  {\n    title: \"Sobre InfoJobs\",\n    links: [\n      {\n        label: \"InfoJobs hoy\",\n        href: \"https://nosotros.infojobs.net/\",\n      },\n      {\n        label: \"Trabaja con nosotros\",\n        href: \"https://www.infojobs.net/candidate/candidate-login/candidate-login.xhtml?error=caducado&dgv=8615867714346349222\",\n      },\n      {\n        label: \"Ofertas de empleo\",\n        href: \"https://www.infojobs.net/ofertas-empleo\",\n      },\n    ],\n  },\n  {\n    title: \"+ InfoJobs\",\n    links: [\n      {\n        label: \"InfoJobs Awards\",\n        href: \"https://awards.infojobs.net/\",\n      },\n      {\n        label: \"InfoJobs Academy\",\n        href: \"https://infojobsacademy.com/\",\n      },\n      {\n        label: \"Orientación laboral\",\n        href: \"https://orientacion-laboral.infojobs.net/\",\n      },\n      {\n        label: \"InfoJobs Formación\",\n        href: \"https://formacion.infojobs.net/\",\n      },\n      {\n        label: \"Blog empresas\",\n        href: \"https://recursos-humanos.infojobs.net/\",\n      },\n      {\n        label: \"Offerte di lavoro in Italia\",\n        href: \"https://www.infojobs.it/\",\n      },\n    ],\n  },\n  {\n    title: \"Prensa\",\n    links: [\n      {\n        label: \"Indicadores de InfoJobs\",\n        href: \"https://nosotros.infojobs.net/indicadores-infojobs\",\n      },\n      {\n        label: \"Notas de prensa\",\n        href: \"https://nosotros.infojobs.net/prensa/notas-prensa\",\n      },\n      {\n        label: \"Contacto de prensa\",\n        href: \"https://nosotros.infojobs.net/contacto-prensa/contacto-de-prensa\",\n      },\n    ],\n  },\n]\n---\n\n<div\n  class=\"px-[40px] items-center md:justify-between md:items-start flex flex-col md:flex-row\"\n>\n  {\n    linksInfo.map(({ title, links }, index) => {\n      return (\n        <div class={`${index === 0 ? \"\" : \"hidden sm:block\"}`}>\n          <h2 class=\"text-black font-semibold text-[18px] hidden md:block mb-2\">\n            {title}\n          </h2>\n\n          <ul class=\"flex flex-row  md:flex-col underline md:no-underline gap-4 md:gap-0\">\n            {links.map(({ label, href, showOnMobile }) => {\n              return (\n                <li\n                  class:list={[\n                    `mb-2 hover:underline hover:underline-offset-[3px]`,\n                    showOnMobile ? \"\" : \"hidden md:block\",\n                  ]}\n                >\n                  <a href={href} class=\"text-[14px] leading-6\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label={label}>\n                    {label}\n                  </a>\n                </li>\n              )\n            })}\n          </ul>\n        </div>\n      )\n    })\n  }\n</div>\n"
  },
  {
    "path": "src/components/LiteYoutube.astro",
    "content": "---\nimport Icon from \"./ui/Icon.astro\"\n\ninterface Props {\n\tvideoId: string\n\ttitle?: string\n}\n\nconst { videoId, title } = Astro.props\n---\n\n<lite-youtube\n\tclass=\"rounded-2xl bg-cover h-[570px] w-80 snap-center\"\n\tvideoid={videoId}\n\ttabindex=\"0\"\n\taria-label=\"button\"\n>\n\t<a\n\t\thref={`https://www.youtube.com/shorts/${videoId}`}\n\t\tclass=\"lty-playbtn p-4 pl-[18px] bg-white rounded-full absolute bottom-6 right-6 hover:scale-110 transition-transform\"\n\t\ttitle={title}\n\t\trole=\"button\"\n\t\ttabindex=\"0\"\n\t>\n\t\t<span class=\"lyt-visually-hidden\">{title}</span>\n\t\t<Icon name=\"play\" class=\"text-primary\" />\n\t</a>\n</lite-youtube>\n\n<script>\n\t// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n\t// @ts-nocheck\n\n\t/*\n\tComponent extracted from: https://github.com/paulirish/lite-youtube-embed/tree/master\n\t*/\n\n\t/**\n\t * A lightweight youtube embed. Still should feel the same to the user, just MUCH faster to initialize and paint.\n\t *\n\t * Thx to these as the inspiration\n\t *   https://storage.googleapis.com/amp-vs-non-amp/youtube-lazy.html\n\t *   https://autoplay-youtube-player.glitch.me/\n\t *\n\t * Once built it, I also found these:\n\t *   https://github.com/ampproject/amphtml/blob/master/extensions/amp-youtube (👍👍)\n\t *   https://github.com/Daugilas/lazyYT\n\t *   https://github.com/vb/lazyframe\n\t */\n\tclass LiteYTEmbed extends HTMLElement {\n\t\tconnectedCallback() {\n\t\t\tconst video = this.getAttribute(\"videoid\").split(\"?\")\n\t\t\tthis.videoId = video[0]\n\t\t\tthis.short = video[1]\n\n\t\t\tlet playBtnEl = this.querySelector(\".lty-playbtn\")\n\t\t\t// A label for the button takes priority over a [playlabel] attribute on the custom-element\n\t\t\tthis.playLabel =\n\t\t\t\t(playBtnEl && playBtnEl.textContent.trim()) ||\n\t\t\t\tthis.getAttribute(\"playlabel\") ||\n\t\t\t\t\"Reproducir presentación de La Velada del Año\"\n\n\t\t\tthis.dataset.title = this.getAttribute(\"title\") || \"\"\n\n\t\t\t/**\n\t\t\t * Lo, the youtube poster image!  (aka the thumbnail, image placeholder, etc)\n\t\t\t *\n\t\t\t * See https://github.com/paulirish/lite-youtube-embed/blob/master/youtube-thumbnail-urls.md\n\t\t\t */\n\t\t\tif (!this.style.backgroundImage) {\n\t\t\t\tthis.style.backgroundImage = `url(\"https://i.ytimg.com/vi/${this.videoId}/hqdefault.jpg\")`\n\t\t\t\tthis.upgradePosterImage()\n\t\t\t}\n\n\t\t\t// Set up play button, and its visually hidden label\n\t\t\tif (!playBtnEl) {\n\t\t\t\tplayBtnEl = document.createElement(\"button\")\n\t\t\t\tplayBtnEl.type = \"button\"\n\t\t\t\tplayBtnEl.classList.add(\"lty-playbtn\")\n\t\t\t\tthis.append(playBtnEl)\n\t\t\t}\n\t\t\tif (!playBtnEl.textContent) {\n\t\t\t\tconst playBtnLabelEl = document.createElement(\"span\")\n\t\t\t\tplayBtnLabelEl.className = \"lyt-visually-hidden\"\n\t\t\t\tplayBtnLabelEl.textContent = this.playLabel\n\t\t\t\tplayBtnEl.append(playBtnLabelEl)\n\t\t\t}\n\n\t\t\tthis.addNoscriptIframe()\n\n\t\t\t// On hover (or tap), warm up the TCP connections we're (likely) about to use.\n\t\t\tthis.addEventListener(\"pointerover\", LiteYTEmbed.warmConnections, { once: true })\n\n\t\t\t// Once the user clicks, add the real iframe and drop our play button\n\t\t\t// TODO: In the future we could be like amp-youtube and silently swap in the iframe during idle time\n\t\t\t//   We'd want to only do this for in-viewport or near-viewport ones: https://github.com/ampproject/amphtml/pull/5003\n\t\t\tthis.addEventListener(\"click\", this.activate)\n\n\t\t\t// For accessibility, handle keypresses as well\n\t\t\tthis.addEventListener(\"keydown\", this.handleKeyPress)\n\n\t\t\t// Chrome & Edge desktop have no problem with the basic YouTube Embed with ?autoplay=1\n\t\t\t// However Safari desktop and most/all mobile browsers do not successfully track the user gesture of clicking through the creation/loading of the iframe,\n\t\t\t// so they don't autoplay automatically. Instead we must load an additional 2 sequential JS files (1KB + 165KB) (un-br) for the YT Player API\n\t\t\t// TODO: Try loading the the YT API in parallel with our iframe and then attaching/playing it. #82\n\t\t\tthis.needsYTApi =\n\t\t\t\tthis.hasAttribute(\"js-api\") ||\n\t\t\t\tnavigator.vendor.includes(\"Apple\") ||\n\t\t\t\tnavigator.userAgent.includes(\"Mobi\")\n\t\t}\n\n\t\t/**\n\t\t * Add a <link rel={preload | preconnect} ...> to the head\n\t\t */\n\t\tstatic addPrefetch(kind, url, as) {\n\t\t\tconst linkEl = document.createElement(\"link\")\n\t\t\tlinkEl.rel = kind\n\t\t\tlinkEl.href = url\n\t\t\tif (as) {\n\t\t\t\tlinkEl.as = as\n\t\t\t}\n\t\t\tdocument.head.append(linkEl)\n\t\t}\n\n\t\t/**\n\t\t * Begin pre-connecting to warm up the iframe load\n\t\t * Since the embed's network requests load within its iframe,\n\t\t *   preload/prefetch'ing them outside the iframe will only cause double-downloads.\n\t\t * So, the best we can do is warm up a few connections to origins that are in the critical path.\n\t\t *\n\t\t * Maybe `<link rel=preload as=document>` would work, but it's unsupported: http://crbug.com/593267\n\t\t * But TBH, I don't think it'll happen soon with Site Isolation and split caches adding serious complexity.\n\t\t */\n\t\tstatic warmConnections() {\n\t\t\tif (LiteYTEmbed.preconnected) return\n\n\t\t\t// The iframe document and most of its subresources come right off youtube.com\n\t\t\tLiteYTEmbed.addPrefetch(\"preconnect\", \"https://www.youtube-nocookie.com\")\n\t\t\t// The botguard script is fetched off from google.com\n\t\t\tLiteYTEmbed.addPrefetch(\"preconnect\", \"https://www.google.com\")\n\n\t\t\t// Not certain if these ad related domains are in the critical path. Could verify with domain-specific throttling.\n\t\t\tLiteYTEmbed.addPrefetch(\"preconnect\", \"https://googleads.g.doubleclick.net\")\n\t\t\tLiteYTEmbed.addPrefetch(\"preconnect\", \"https://static.doubleclick.net\")\n\n\t\t\tLiteYTEmbed.preconnected = true\n\t\t}\n\n\t\tfetchYTPlayerApi() {\n\t\t\tif (window.YT || (window.YT && window.YT.Player)) return\n\n\t\t\t/* global YT */\n\t\t\tthis.ytApiPromise = new Promise((resolve, reject) => {\n\t\t\t\tconst el = document.createElement(\"script\")\n\t\t\t\tel.src = \"https://www.youtube.com/iframe_api\"\n\t\t\t\tel.async = true\n\t\t\t\tel.onload = (_) => {\n\t\t\t\t\tYT.ready(resolve)\n\t\t\t\t}\n\t\t\t\tel.onerror = reject\n\t\t\t\tthis.append(el)\n\t\t\t})\n\t\t}\n\n\t\t/** Return the YT Player API instance. (Public L-YT-E API) */\n\t\tasync getYTPlayer() {\n\t\t\tif (!this.playerPromise) {\n\t\t\t\tawait this.activate()\n\t\t\t}\n\n\t\t\treturn this.playerPromise\n\t\t}\n\n\t\tasync addYTPlayerIframe() {\n\t\t\tthis.fetchYTPlayerApi()\n\t\t\tawait this.ytApiPromise\n\n\t\t\tconst videoPlaceholderEl = document.createElement(\"div\")\n\t\t\tthis.append(videoPlaceholderEl)\n\n\t\t\tconst paramsObj = Object.fromEntries(this.getParams().entries())\n\n\t\t\tthis.playerPromise = new Promise((resolve) => {\n\t\t\t\tconst player = new YT.Player(videoPlaceholderEl, {\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\tvideoId: this.videoId,\n\t\t\t\t\tplayerVars: paramsObj,\n\t\t\t\t\tevents: {\n\t\t\t\t\t\tonReady: (event) => {\n\t\t\t\t\t\t\tevent.target.playVideo()\n\t\t\t\t\t\t\tresolve(player)\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\n\t\t// Add the iframe within <noscript> for indexability discoverability. See https://github.com/paulirish/lite-youtube-embed/issues/105\n\t\taddNoscriptIframe() {\n\t\t\tconst iframeEl = this.createBasicIframe()\n\t\t\tconst noscriptEl = document.createElement(\"noscript\")\n\t\t\t// Appending into noscript isn't equivalant for mysterious reasons: https://html.spec.whatwg.org/multipage/scripting.html#the-noscript-element\n\t\t\tnoscriptEl.innerHTML = iframeEl.outerHTML\n\t\t\tthis.append(noscriptEl)\n\t\t}\n\n\t\tgetParams() {\n\t\t\tconst params = new URLSearchParams(this.getAttribute(\"params\") || [])\n\t\t\tparams.append(\"autoplay\", \"1\")\n\t\t\tparams.append(\"playsinline\", \"1\")\n\t\t\tparams.append(\"color\", \"white\")\n\t\t\treturn params\n\t\t}\n\n\t\tasync activate() {\n\t\t\tif (this.classList.contains(\"lyt-activated\")) return\n\t\t\tconst playBtnEl = this.querySelector(\".lty-playbtn\")\n\t\t\tif (playBtnEl && playBtnEl.hasAttribute(\"href\")) {\n\t\t\t\tplayBtnEl.removeAttribute(\"href\")\n\t\t\t}\n\t\t\tthis.classList.add(\"lyt-activated\")\n\n\t\t\tif (this.style.backgroundImage !== \"unset\") {\n\t\t\t\tthis.style.backgroundImage = \"unset\"\n\t\t\t}\n\n\t\t\tif (this.needsYTApi) {\n\t\t\t\treturn this.addYTPlayerIframe(this.getParams())\n\t\t\t}\n\n\t\t\tconst iframeEl = this.createBasicIframe()\n\t\t\tthis.append(iframeEl)\n\n\t\t\t// Set focus for a11y\n\t\t\tiframeEl.focus()\n\t\t}\n\n\t\thandleKeyPress(event) {\n\t\t\tif (event.code === \"Enter\" || event.code === \"Space\") {\n\t\t\t\tthis.activate()\n\t\t\t}\n\t\t}\n\n\t\tcreateBasicIframe() {\n\t\t\tconst iframeEl = document.createElement(\"iframe\")\n\t\t\tiframeEl.width = 560\n\t\t\tiframeEl.height = 315\n\t\t\t// No encoding necessary as [title] is safe. https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#:~:text=Safe%20HTML%20Attributes%20include\n\t\t\tiframeEl.title = this.playLabel\n\t\t\tiframeEl.allow = \"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\"\n\t\t\tiframeEl.allowFullscreen = true\n\t\t\t// AFAIK, the encoding here isn't necessary for XSS, but we'll do it only because this is a URL\n\t\t\t// https://stackoverflow.com/q/64959723/89484\n\t\t\tiframeEl.src = !this.short\n\t\t\t\t? `https://www.youtube-nocookie.com/embed/${encodeURIComponent(this.videoId)}?${this.getParams().toString()}`\n\t\t\t\t: `https://www.youtube.com/embed/${encodeURIComponent(this.videoId)}?${this.getParams().toString()}&${this.short}`\n\t\t\treturn iframeEl\n\t\t}\n\n\t\t/**\n\t\t * In the spirit of the `lowsrc` attribute and progressive JPEGs, we'll upgrade the reliable\n\t\t * poster image to a higher resolution one, if it's available.\n\t\t * Interestingly this sddefault webp is often smaller in filesize, but we will still attempt it second\n\t\t * because getting _an_ image in front of the user if our first priority.\n\t\t *\n\t\t * See https://github.com/paulirish/lite-youtube-embed/blob/master/youtube-thumbnail-urls.md for more details\n\t\t */\n\t\tupgradePosterImage() {\n\t\t\t// Defer to reduce network contention.\n\t\t\tsetTimeout(() => {\n\t\t\t\tconst webpUrl = `https://i.ytimg.com/vi_webp/${this.videoId}/sddefault.webp`\n\t\t\t\tconst img = new Image()\n\t\t\t\timg.fetchPriority = \"low\" // low priority to reduce network contention\n\t\t\t\timg.referrerpolicy = \"origin\" // Not 100% sure it's needed, but https://github.com/ampproject/amphtml/pull/3940\n\t\t\t\timg.src = webpUrl\n\t\t\t\timg.onload = (e) => {\n\t\t\t\t\t// A pretty ugly hack since onerror won't fire on YouTube image 404. This is (probably) due to\n\t\t\t\t\t// Youtube's style of returning data even with a 404 status. That data is a 120x90 placeholder image.\n\t\t\t\t\t// … per \"annoying yt 404 behavior\" in the .md\n\t\t\t\t\tconst noAvailablePoster = e.target.naturalHeight === 90 && e.target.naturalWidth === 120\n\t\t\t\t\tif (noAvailablePoster) return\n\n\t\t\t\t\tthis.style.backgroundImage = `url(\"${webpUrl}\")`\n\t\t\t\t}\n\t\t\t}, 100)\n\t\t}\n\t}\n\t// Register custom element\n\tcustomElements.define(\"lite-youtube\", LiteYTEmbed)\n</script>\n\n<style is:global>\n\tlite-youtube {\n\t\tbackground-color: #000;\n\t\tposition: relative;\n\t\tdisplay: block;\n\t\tcontain: content;\n\t\tbackground-position: center center;\n\t\tbackground-size: cover;\n\t\tcursor: pointer;\n\t\taspect-ratio: 16/9;\n\t\twidth: 100%;\n\t\theight: auto;\n\t\tborder: 2px solid var(--color-accent);\n\t\ttransition: all 0.3s ease;\n\t\tbox-shadow: 0px 0px 15px rgb(212, 255, 0, 0.1);\n\t}\n\n\t/* gradient */\n\tlite-youtube::before {\n\t\tcontent: attr(data-title);\n\t\tdisplay: block;\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\t/* Pixel-perfect port of YT's gradient PNG, using https://github.com/bluesmoon/pngtocss plus optimizations */\n\t\tbackground-image: linear-gradient(\n\t\t\t180deg,\n\t\t\trgb(0 0 0 / 67%) 0%,\n\t\t\trgb(0 0 0 / 54%) 14%,\n\t\t\trgb(0 0 0 / 15%) 54%,\n\t\t\trgb(0 0 0 / 5%) 72%,\n\t\t\trgb(0 0 0 / 0%) 94%\n\t\t);\n\t\theight: 99px;\n\t\twidth: 100%;\n\t\tfont-family: \"YouTube Noto\", Roboto, Arial, Helvetica, sans-serif;\n\t\tcolor: hsl(0deg 0% 93.33%);\n\t\ttext-shadow: 0 0 2px rgba(0, 0, 0, 0.5);\n\t\tfont-size: 18px;\n\t\tpadding: 25px 20px;\n\t\toverflow: hidden;\n\t\twhite-space: nowrap;\n\t\ttext-overflow: ellipsis;\n\t\tbox-sizing: border-box;\n\t}\n\n\tlite-youtube:hover::before {\n\t\tcolor: white;\n\t}\n\n\t/* responsive iframe with a 16:9 aspect ratio\n    thanks https://css-tricks.com/responsive-iframes/\n*/\n\tlite-youtube::after {\n\t\tcontent: \"\";\n\t\tdisplay: block;\n\t\tpadding-bottom: calc(100% / (16 / 9));\n\t}\n\tlite-youtube > iframe {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\tborder: 0;\n\t}\n\n\t/* Post-click styles */\n\tlite-youtube.lyt-activated {\n\t\tcursor: unset;\n\t}\n\tlite-youtube.lyt-activated::before,\n\tlite-youtube.lyt-activated > .lty-playbtn {\n\t\topacity: 0;\n\t\tpointer-events: none;\n\t}\n\n\t.lyt-visually-hidden {\n\t\tclip: rect(0 0 0 0);\n\t\tclip-path: inset(50%);\n\t\theight: 1px;\n\t\toverflow: hidden;\n\t\tposition: absolute;\n\t\twhite-space: nowrap;\n\t\twidth: 1px;\n\t}\n</style>"
  },
  {
    "path": "src/components/OportunidadesTikTok.astro",
    "content": "---\nconst cardsOportunidades = [\n  {\n    title1: \"Oferta de empleo\",\n    title2: \"Miles de oportunidades\",\n    img: \"./img/pre-footer/oferta-empleo.webp\",\n    gradient: \"bg-gradient-to-t from-[#8BCFAD] to-[#E6F6EE]\",\n    colorTitle: \"text-[#0E8247]\",\n    imageClass: \"p-4 sm:p-8 md:p-4 lg:p-8 !pb-0\",\n    href: \"https://www.infojobs.net/\",\n    track: \"job_offers\",\n  },\n  {\n    title1: \"InfoJobs en TikTok\",\n    title2: \"Consejos para encontrar trabajo\",\n    img: \"./img/pre-footer/info-tiktok.webp\",\n    gradient: \"bg-gradient-to-t from-[#FFE4A2] to-[#FEF6DB]\",\n    colorTitle: \"text-[#EFA500]\",\n    imageClass: \"\",\n    href: \"https://www.tiktok.com/@infojobs/playlist/Encontrar%20trabajo-7401023016819378977 \",\n    track: \"tik_tok\",\n  },\n] as const\n---\n\n<div class=\"grid grid-cols-1 sm:grid-cols-2 w-auto h-auto gap-6 sm:gap-[40px]\">\n  {\n    cardsOportunidades.map((card) => (\n      <a\n        class={`group flex flex-col rounded-[16px] pt-4 px-4 md:px-12 lg:px-15 lg:pt-6 xl:pt-10 aspect-[328/436] md:aspect-square w-full overflow-hidden ${card.gradient}`}\n        href={card.href}\n        target=\"_blank\"\n        data-track={card.track}\n      >\n        <p class=\"mt-4 text-2xl font-semibold text-gray-900\">{card.title1}</p>\n        <p class={`mt-2 text-3xl lg:text-5xl font-semibold ${card.colorTitle}`}>\n          {card.title2}\n        </p>\n\n        <div class=\"flex justify-center mt-auto w-full h-auto md:mb-0\">\n          <img\n            class=\"w-full h-full scale-100 transition group-hover:scale-105 group-hover:z-10 object-contain object-bottom\"\n            class:list={card.imageClass}\n            src={card.img}\n            alt=\"InfoJobs\"\n          />\n        </div>\n      </a>\n    ))\n  }\n</div>\n"
  },
  {
    "path": "src/components/PreFooter.astro",
    "content": "---\nimport KingsLeagueInfo from \"@components/KingsLeagueInfo.astro\"\nimport SectionContainer from \"@components/SectionContainer.astro\"\nimport OportunidadesTikTok from \"@components/OportunidadesTikTok.astro\"\nimport Subtitle from \"@components/Subtitle.astro\"\n---\n\n<SectionContainer>\n  <Subtitle>InfoJobs, ¿la de trabajar te la sabes?</Subtitle>\n  <div class=\"flex flex-col gap-10\">\n    <KingsLeagueInfo />\n    <OportunidadesTikTok />\n  </div>\n</SectionContainer>\n"
  },
  {
    "path": "src/components/SectionContainer.astro",
    "content": "<section class=\"mx-auto max-w-7xl w-full\">\n  <div class:list={[\"mx-auto w-full px-4\", Astro.props.class]}>\n    <slot />\n  </div>\n</section>\n"
  },
  {
    "path": "src/components/SocialBest.astro",
    "content": "---\nimport SectionContainer from \"./SectionContainer.astro\"\nimport TiktokVideo from \"./TiktokVideo.astro\"\nimport Icon from \"./ui/Icon.astro\"\nimport Subtitle from \"./Subtitle.astro\"\n\nconst VIDEOS = [\n  {\n    videoId: \"7222709244125007109\",\n    thumbnailUrl: \"/img/thumbnails/ibai.webp\",\n    title: \"La relación de Ibai con Marcos\",\n  },\n  {\n    videoId: \"7258016065563807003\",\n    thumbnailUrl: \"/img/thumbnails/jijantes.webp\",\n    title: \"Fichaje del nuevo reportero de Jijantes\",\n  },\n  {\n    videoId: \"7343332399662533920\",\n    thumbnailUrl: \"/img/thumbnails/midudev.webp\",\n    title: \"Fichajes de la web de La Velada junto a Midudev\",\n  },\n  {\n    videoId: \"7265231719068880160\",\n    thumbnailUrl: \"/img/thumbnails/cristinini.webp\",\n    title: \"Ganadora de la Beca Infojobs Cristinini\",\n  },\n  {\n    videoId: \"7285448407756393761\",\n    thumbnailUrl: \"/img/thumbnails/marcos.webp\",\n    title: \"Entrevista a Marcos de Olañeta\",\n  },\n] as const\n---\n\n<SectionContainer class=\"px-0\">\n  <div class=\"flex items-center justify-between pb-6 md:pb-12\">\n    <Subtitle class=\"!pb-0\">Trabaja con los mejores</Subtitle>\n\n    <div class=\"hidden md:flex items-center gap-x-4\">\n      <button\n        class=\"bg-[#E2E2E5] text-[#636365] opacity-45 p-1 rounded-full enabled:hover:scale-110 transition-all enabled:active:scale-100\"\n        id=\"left-button\"\n        disabled=\"true\"\n        aria-label=\"Ir al elemento anterior\"\n      >\n        <Icon name=\"leftarrow\" />\n      </button>\n      <button\n        class=\"bg-[#E2E2E5] text-[#636365] p-1 rounded-full enabled:hover:scale-110 transition-all enabled:active:scale-100\"\n        id=\"right-button\"\n        aria-label=\"Ir al siguiente elemento\"\n      >\n        <Icon name=\"rightarrow\" />\n      </button>\n    </div>\n  </div>\n\n  <div\n    class=\"relative carousel-container -mr-4 pr-4 md:mr-0 md:pr-0\"\n    id=\"carousel-container\"\n    style=\"--left-opacity: 0; --right-opacity: 1;\"\n  >\n    <div\n      class=\"flex overflow-scroll custom-scrollbar gap-x-4 md:gap-x-8 snap-mandatory snap-x -mr-4 pr-4 md:mr-0 md:pr-0\"\n      id=\"carousel\"\n    >\n      {\n        VIDEOS.map(({ videoId, thumbnailUrl, title }) => (\n          <TiktokVideo\n            videoId={videoId}\n            thumbnailUrl={thumbnailUrl}\n            title={title}\n          />\n        ))\n      }\n    </div>\n  </div>\n</SectionContainer>\n\n<style>\n  .custom-scrollbar::-webkit-scrollbar {\n    display: none;\n  }\n\n  .custom-scrollbar {\n    -ms-overflow-style: none;\n    scrollbar-width: none;\n  }\n\n  .carousel-container:before {\n    background-image: linear-gradient(to left, transparent, #fff);\n    content: \"\";\n    height: 570px;\n    left: 0;\n    opacity: var(--left-opacity);\n    pointer-events: none;\n    position: absolute;\n    top: 0;\n    transition: opacity cubic-bezier(0.4, 0, 0.2, 1) 150ms;\n    width: 64px;\n    z-index: 10;\n  }\n\n  .carousel-container:after {\n    background-image: linear-gradient(to right, transparent, #fff);\n    content: \"\";\n    height: 570px;\n    opacity: var(--right-opacity);\n    pointer-events: none;\n    position: absolute;\n    right: 0;\n    top: 0;\n    transition: opacity cubic-bezier(0.4, 0, 0.2, 1) 150ms;\n    width: 64px;\n    z-index: 10;\n  }\n\n  @media (max-width: 768px) {\n    .carousel-container:before {\n      opacity: 0 !important;\n    }\n\n    .carousel-container:after {\n      opacity: 0 !important;\n    }\n  }\n</style>\n\n<script>\n  const rightButton = document.querySelector(\n    \"#right-button\"\n  ) as HTMLButtonElement\n  const leftButton = document.querySelector(\"#left-button\") as HTMLButtonElement\n  const carousel = document.querySelector(\"#carousel\") as HTMLDivElement\n  const carouselContainer = document.querySelector(\n    \"#carousel-container\"\n  ) as HTMLDivElement\n\n  leftButton.addEventListener(\"click\", () => {\n    carousel.scrollTo({\n      left: carousel.scrollLeft - 320,\n      behavior: \"smooth\",\n    })\n  })\n\n  rightButton.addEventListener(\"click\", () => {\n    carousel.scrollTo({\n      left: carousel.scrollLeft + 320,\n      behavior: \"smooth\",\n    })\n  })\n\n  carousel.addEventListener(\"scroll\", () => {\n    const tolerance = 2 // 0 + 2px to account for floating point errors\n\n    const updateButtonState = (button: HTMLButtonElement, disable: boolean) => {\n      button.classList.toggle(\"opacity-45\", disable)\n      button.disabled = disable\n    }\n\n    const updateOpacity = (property: string, value: string) => {\n      carouselContainer.style.setProperty(property, value)\n    }\n\n    if (carousel.scrollLeft <= tolerance) {\n      updateButtonState(leftButton, true)\n    } else {\n      updateButtonState(leftButton, false)\n    }\n\n    if (\n      carousel.scrollLeft + carousel.clientWidth >=\n      carousel.scrollWidth - tolerance\n    ) {\n      updateButtonState(rightButton, true)\n      updateOpacity(\"--right-opacity\", \"0\")\n    } else {\n      updateButtonState(rightButton, false)\n      updateOpacity(\"--right-opacity\", \"1\")\n    }\n\n    if (carousel.scrollLeft > tolerance) {\n      updateOpacity(\"--left-opacity\", \"1\")\n    } else {\n      updateOpacity(\"--left-opacity\", \"0\")\n    }\n  })\n</script>\n"
  },
  {
    "path": "src/components/StandsInterviews.astro",
    "content": "---\nimport InfographicBody from \"./InfographicBody.astro\"\nimport InfographicHeader from \"./InfographicHeader.astro\"\n\nconst standsInterviews = [\n  {\n    image: \"/img/bento-info-modal-cards/sincerity-and-trust.webp\",\n    title: \"Sinceridad y confianza\",\n    description:\n      \"¡Si te han llamado será por algo! Demuestra que lo que te falta de experiencia, te sobra de aptitud.\",\n    firstBgColor: \"#B4E5CD\",\n    secondBgColor: \"#E1F4EB\",\n    textColor: \"#008949\",\n  },\n  {\n    image: \"/img/bento-info-modal-cards/show-enthusiasm.webp\",\n    title: \"Demuestra entusiasmo\",\n    description:\n      \"Infórmate sobre la empresa y el puesto para explicar al entrevistador/a tu interés.\",\n    firstBgColor: \"#FDECBE\",\n    secondBgColor: \"#FFF7E4\",\n    textColor: \"#B08B2B\",\n  },\n  {\n    image: \"/img/bento-info-modal-cards/focus-on-your-skills.webp\",\n    title: \"Céntrate en tus habilidades\",\n    description:\n      \"Muestra iniciativa y remarca tus conocimientos: tecnologías, herramientas digitales, idiomas o deportes\",\n    firstBgColor: \"#FFBFB5\",\n    secondBgColor: \"#FBE9E7\",\n    textColor: \"#FF523C\",\n  },\n  {\n    image: \"/img/bento-info-modal-cards/learning-ability.webp\",\n    title: \"Capacidad de aprendizaje\",\n    description:\n      \"Si no tienes experiencia laboral, muestra tus ganas por seguir formándote, dentro y fuera de la compañía.\",\n    firstBgColor: \"#64C6F6\",\n    secondBgColor: \"#D2EEFA\",\n    textColor: \"#085C81\",\n  },\n  {\n    image: \"/img/bento-info-modal-cards/questions-and-answers.webp\",\n    title: \"Practica preguntas y respuestas\",\n    description:\n      \"Prepárate posibles respuestas y preguntas sobre la compañía y tu rol, ¡así verán que vas a por todas!\",\n    firstBgColor: \"#88DBFF\",\n    secondBgColor: \"#E1F8FF\",\n    textColor: \"#0073AA\",\n  },\n  {\n    image: \"/img/bento-info-modal-cards/double-authenticity.webp\",\n    title: \"La autenticidad puntúa doble\",\n    description:\n      \"Mira a los ojos, exprésate con las manos, tú tienes el control de la situación. ¡Y sonríe de forma natural!\",\n    firstBgColor: \"#FFBEBF\",\n    secondBgColor: \"#FBE9E7\",\n    textColor: \"#DF4D3A\",\n  },\n] as const\n\nconst { infographicId } = Astro.props\n---\n\n<section\n  id={`infographic-${infographicId}`}\n  class=\"mx-auto px-4 max-w-7xl w-full flex-col md:gap-[50px] py-[72px] hidden\"\n>\n  <InfographicHeader\n    badgeText=\"Destaca en las entrevistas\"\n    title=\"¿Quieres triunfar en una entrevista aunque no tengas experiencia para ese trabajo?\"\n    subtitle=\"¡Sin problema!\"\n  />\n\n  <InfographicBody bentoInfoModalCards={standsInterviews} />\n</section>\n\n"
  },
  {
    "path": "src/components/Subtitle.astro",
    "content": "<h2 class:list={[\"font-semibold text-xl pb-4 sm:pb-6 sm:text-2xl md:text-4xl md:pb-12\", Astro.props.class]}>\n    <slot />\n</h2>"
  },
  {
    "path": "src/components/TiktokVideo.astro",
    "content": "---\nimport Icon from \"./ui/Icon.astro\"\n\ninterface Props {\n  videoId: string\n  thumbnailUrl: string\n  title: string\n}\n\nconst { videoId, thumbnailUrl, title } = Astro.props\n---\n\n<tiktok-video\n  class=\"rounded-[16px] h-[570px] w-80 snap-center bg-black relative shrink-0 cursor-pointer bg-center bg-[length:100%] hover:bg-[length:105%] transition-[background-size]\"\n  videoid={videoId}\n  thumbnailurl={thumbnailUrl}\n  data-title={title}\n  data-track=\"play_video\"\n  aria-label=\"Reproducir video\"\n  role=\"button\"\n  tabindex=\"0\"\n>\n  <div\n    class=\"p-4 pl-[18px] bg-white rounded-full absolute bottom-6 right-6 hover:scale-110 transition-transform duration-300\"\n    id=`Id${videoId}`\n    title={title}\n  >\n    <Icon name=\"play\" class=\"text-primary\" />\n  </div>\n</tiktok-video>\n\n<script>\n  class TiktokVideo extends HTMLElement {\n    videoId?: string\n\n    connectedCallback() {\n      const thumbnailUrl = this.getAttribute(\"thumbnailurl\")\n      this.videoId = this.getAttribute(\"videoid\")!\n\n      this.style.backgroundImage = `url(${thumbnailUrl})`\n\n      this.addEventListener(\"click\", this.activateVideo)\n      this.addEventListener(\"keydown\", this.handleKeyPress)\n    }\n\n    activateVideo() {\n      this.style.backgroundImage = \"unset\"\n\n      this.querySelector(`#Id${this.videoId}`)?.remove()\n\n      const iframeEl = this.createIframe()\n      this.append(iframeEl)\n      iframeEl.focus()\n\n      this.unMutePlayerByDefault()\n    }\n\n    handleKeyPress(event: KeyboardEvent) {\n      if (event.code === \"Enter\" || event.code === \"Space\") {\n        this.activateVideo()\n      }\n    }\n\n    createIframe() {\n      const iframeEl = document.createElement(\"iframe\")\n      iframeEl.width = \"320\"\n      iframeEl.height = \"570\"\n      iframeEl.classList.add(\"rounded-2xl\", \"w-full\", \"h-full\", \"snap-center\")\n      iframeEl.title = this.getAttribute(\"data-title\")!\n      iframeEl.allow =\n        \"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; transparency\"\n      iframeEl.allowFullscreen = true\n      iframeEl.src = `https://www.tiktok.com/player/v1/${this.videoId}?autoplay=1`\n\n      return iframeEl\n    }\n\n    unMutePlayerByDefault() {\n      const messageHandler = (event: MessageEvent) => {\n        if (\n          event.origin === \"https://www.tiktok.com\" &&\n          event.data.type === \"onPlayerReady\"\n        ) {\n          this.querySelector(\"iframe\")!.contentWindow!.postMessage(\n            { type: \"unMute\", \"x-tiktok-player\": true },\n            \"*\"\n          )\n\n          window.removeEventListener(\"message\", messageHandler)\n        }\n      }\n\n      window.addEventListener(\"message\", messageHandler)\n    }\n  }\n\n  customElements.define(\"tiktok-video\", TiktokVideo)\n</script>\n"
  },
  {
    "path": "src/components/YourNextJob.astro",
    "content": "---\nimport InfographicBody from \"./InfographicBody.astro\"\nimport InfographicHeader from \"./InfographicHeader.astro\"\nimport InfographicTips from \"./InfographicTips.astro\"\n\nconst yourNextJobContent = [\n    {\n        image: \"/img/bento-info-modal-cards/style-your-cv.webp\",\n        title: \"Pon guapo tu CV\",\n        description: \"Actualízalo, sube una foto profesional ¡y rellena tus habilidades/skills! (sobre todo si te falta experiencia).\",\n        firstBgColor: \"#FDECBE\",\n        secondBgColor: \"#FFF7E4\",\n        textColor: \"#B08B2B\",\n\n    },\n    {\n        image: \"/img/bento-info-modal-cards/search-ideal-offer.webp\",\n        title: \"Busca tu oferta ideal\",\n        description: \"Utiliza las recomendaciones que te ofrece InfoJobs o busca a tu medida según el sector que más te interesa.\",\n        firstBgColor: \"#B4E5CD\",\n        secondBgColor: \"#E1F4EB\",\n        textColor: \"#008949\",\n    },\n    {\n        image: \"/img/bento-info-modal-cards/register.webp\",\n        title: \"¡Inscríbete!\",\n        description: \"Lee bien la oferta, ajusta tu CV y adjúntalo. Y no olvides añadir una carta de presentación personalizada a la oferta. ¡Todo suma!\",\n        firstBgColor: \"#BADAE8\",\n        secondBgColor: \"#E3EFF5\",\n        textColor: \"#006895\",\n    },\n    {\n        image: \"/img/bento-info-modal-cards/you-are-their-candidate.webp\",\n        title: \"Ya eres su candidato/a\",\n        description: \"Toca esperar y cruzar los dedos, pero valora inscribirte en otras ofertas que también te interesen\",\n        firstBgColor: \"#FFD1C8\",\n        secondBgColor: \"#FBE9E7\",\n        textColor: \"#FF523C\",\n    }\n] as const\nconst { infographicId } = Astro.props\n---\n\n<section\n  id={`infographic-${infographicId}`}\n  class=\"mx-auto px-4 max-w-7xl w-full flex-col md:gap-[50px] py-[72px] hidden\"\n>\n  <InfographicHeader\n    badgeText=\"Sácale partido a InfoJobs\"\n    title=\"¿Quieres conseguir tu próximo empleo con InfoJobs?\"\n    subtitle=\"¡Vamos a ello!\"\n  />\n\n  <InfographicBody bentoInfoModalCards={yourNextJobContent} />\n  <InfographicTips />\n</section>\n"
  },
  {
    "path": "src/components/ui/Button.astro",
    "content": "---\nimport Icon from \"@ui/Icon.astro\"\n\ninterface ButtonProps {\n  variant?: \"solid\" | \"bordered\" | \"light\" | \"ghost\" | \"flat\"\n  color?: \"default\" | \"primary\" | \"secondary\" | \"success\" | \"warning\" | \"danger\"\n  size?: \"default\" | \"sm\" | \"lg\" | \"full\" | \"icon\"\n  radius?: \"none\" | \"lg\" | \"xl\" | \"xxl\" | \"full\" | string\n  class?: string\n  type?: \"button\" | \"submit\" | \"reset\"\n  href?: string\n  as?: \"button\" | \"link\"\n  role?: \"button\" | \"link\"\n  disabled?: boolean\n  icon?: string\n  iconPosition?: \"left\" | \"right\"\n  block?: boolean\n  iconOnly?: boolean\n  loading?: boolean\n  ariaLabel?: string\n  track?: string\n  disableSaturateHover?: boolean\n}\n\n// Estilos por variante\nconst solid = {\n  default: \"bg-neutral-300 text-neutral-900\",\n  primary: \"bg-primary text-white\",\n  secondary: \"bg-accent text-white\",\n  success: \"bg-ij-green text-white\",\n  warning: \"bg-ij-yellow text-white\",\n  danger: \"bg-red-500 text-white\",\n  foreground: \"bg-black text-white\",\n}\n\nconst bordered = {\n  default: \"border-2 border-neutral-300 text-neutral-900\",\n  primary: \"border-2 border-primary text-primary\",\n  secondary: \"border-2 border-gray-500 text-gray-500\",\n  success: \"border-2 border-ij-green text-ij-green\",\n  warning: \"border-2 border-ij-yellow text-yellow-500\",\n  danger: \"border-2 border-red-500 text-red-500\",\n  foreground: \"border-2 border-black text-black\",\n}\n\nconst light = {\n  default: \"border-transparent text-black hover:bg-neutral-300\",\n  primary: \"border-transparent text-primary hover:bg-primary/20\",\n  secondary: \"border-transparent text-accent hover:bg-accent/20\",\n  success: \"border-transparent text-ij-green hover:bg-ij-green/20\",\n  warning: \"border-transparent text-ij-yellow hover:bg-ij-yellow/20\",\n  danger: \"border-transparent text-red-500 hover:bg-ij-red/20\",\n  foreground: \"border-transparent text-black hover:bg-black/20\",\n}\n\nconst ghost = {\n  default: \"border-2 border-neutral-300 text-neutral-900 hover:bg-neutral-300\",\n  primary:\n    \"border-2 border-primary text-primary hover:bg-primary hover:text-white\",\n  secondary: \"border-2 border-gray-500 text-gray-500 hover:bg-accent\",\n  success:\n    \"border-2 border-ij-green text-ij-green hover:bg-ij-green hover:text-white\",\n  warning:\n    \"border-2 border-ij-yellow text-ij-yellow hover:bg-ij-yellow hover:text-white\",\n  danger: \"border-2 border-ij-red text-ij-red hover:bg-ij-red hover:text-white\",\n  foreground:\n    \"border-2 border-black text-black hover:bg-black hover:text-white\",\n}\n\nconst flat = {\n  default: \"bg-neutral-300/40 text-neutral-900\",\n  primary: \"bg-primary/20 text-primary\",\n  secondary: \"bg-accent/20 text-accent\",\n  success: \"bg-ij-green/20 text-ij-green\",\n  warning: \"bg-ij-yellow/20 text-ij-yellow\",\n  danger: \"bg-ij-red/20 text-ij-red\",\n  foreground: \"bg-black/20 text-black\",\n}\n\nconst variants = {\n  solid,\n  bordered,\n  light,\n  ghost,\n  flat,\n}\n\n// Función para obtener clases por variante y color\nfunction getVariantClasses(\n  variant: keyof typeof variants,\n  color: keyof typeof solid\n) {\n  const variantGroup = variants[variant] || variants.solid // fallback a 'solid'\n  return variantGroup[color] ?? variantGroup.default\n}\n// Clases por tamaño\nconst sizeClasses = {\n  default: \"px-4 py-2 text-lg gap-x-2 font-medium\",\n  sm: \"px-3 min-w-16 h-8 text-sm gap-x-2\",\n  md: \"px-4 min-w-20 h-10 text-base gap-x-2\",\n  lg: \"px-6 min-w-24 h-12 text-lg gap-3 font-medium\",\n  full: \"px-6 w-full py-2.5 text-lg gap-x-3 font-medium\",\n  icon: \"h-10 w-10\",\n}\n\n// Clases por radio\nconst radiusClasses = {\n  none: \"rounded-none\",\n  lg: \"rounded-xl\",\n  xl: \"rounded-2xl\",\n  xxl: \"rounded-4xl\",\n  full: \"rounded-full\",\n}\n\n// Desestructuración de props\nconst {\n  variant = \"solid\",\n  color = \"primary\",\n  size = \"default\",\n  radius = \"xl\",\n  class: extraClasses = \"\",\n  type = \"button\",\n  href,\n  as = \"button\",\n  role = \"button\",\n  disabled = false,\n  icon,\n  iconPosition = \"left\",\n  iconOnly = false,\n  loading = false,\n  ariaLabel,\n  disableSaturateHover = false,\n  track,\n} = Astro.props as ButtonProps\n\n// Definición de clases\nconst customRadiusClass =\n  typeof radius === \"string\" && radius.startsWith(\"rounded-\")\n    ? radius\n    : radiusClasses[radius as keyof typeof radiusClasses] || \"\"\n\nconst variantClasses = getVariantClasses(variant, color)\n\nconst baseClasses = [\n  \"z-0 group relative inline-flex items-center justify-center\",\n  \"box-border appearance-none select-none whitespace-nowrap min-w-max\",\n  \"subpixel-antialiased overflow-hidden tap-highlight-transparent\",\n  \"focus-visible:z-10 focus-visible:outline-2 focus-visible:outline-double\",\n  \"focus-visible:outline-primary focus-visible:outline-offset-2\",\n  \"disabled:opacity-75 disabled:select-none disabled:cursor-not-allowed\",\n  \"disabled:active:scale-100\",\n  \"active:scale-[0.99]\",\n  disableSaturateHover ? \"\" : \"hover:saturate-150\",\n  \"transition-transform-colors-opacity motion-reduce:transition-none\",\n]\n  .filter(Boolean)\n  .join(\" \")\n\nconst buttonClasses = [\n  baseClasses,\n  variantClasses,\n  sizeClasses[size],\n  customRadiusClass,\n  iconOnly ? \"p-2\" : \"\",\n  extraClasses,\n  loading ? \"loading\" : \"\",\n]\n  .filter(Boolean)\n  .join(\" \")\n---\n\n{\n  as === \"button\" ? (\n    <button\n      class={buttonClasses}\n      type={type}\n      disabled={disabled || loading}\n      role={role}\n      aria-label={ariaLabel || (iconOnly ? `${icon} button` : undefined)}\n      aria-busy={loading}\n      aria-hidden={iconOnly ? \"true\" : undefined}\n      data-track={track}\n    >\n      {loading ? (\n        <>\n          <Icon name=\"Spinner\" class=\"animate-spin w-5 h-5\" />\n          <span>Processing...</span>\n        </>\n      ) : (\n        <>\n          {icon && iconPosition === \"left\" && <Icon name={icon} />}\n          <slot />\n          {icon && iconPosition === \"right\" && <Icon name={icon} />}\n        </>\n      )}\n    </button>\n  ) : as === \"link\" && href ? (\n    <a\n      class={buttonClasses}\n      href={href}\n      role={role || \"link\"}\n      aria-label={ariaLabel || (iconOnly ? `${icon} button` : undefined)}\n      aria-hidden={iconOnly ? \"true\" : undefined}\n      data-track={track}\n    >\n      {icon && iconPosition === \"left\" && <Icon name={icon} />}\n      <slot />\n      {icon && iconPosition === \"right\" && <Icon name={icon} />}\n    </a>\n  ) : null\n}\n\n<style>\n  .tap-highlight-transparent {\n    -webkit-tap-highlight-color: transparent;\n  }\n</style>\n"
  },
  {
    "path": "src/components/ui/Icon.astro",
    "content": "---\nconst icons = import.meta.glob(\"@icons/*.astro\", { eager: true })\n\ninterface IconMap {\n  [key: string]: (_props: Record<string, any>) => any\n}\n\nconst iconMap: IconMap = Object.fromEntries(\n  Object.entries(icons).map(([path, module]) => [\n    path.split(\"/\").pop()?.replace(\".astro\", \"\").toLowerCase() || \"\",\n    (module as any).default,\n  ])\n)\n\nconst iconName = Astro.props.name?.toLowerCase()\nconst IconComponent = iconMap[iconName]\n---\n\n{\n  IconComponent ? (\n    <IconComponent {...Astro.props} class={Astro.props.class} />\n  ) : (\n    <div class=\"text-sm\">\n      Icon not found:{\" \"}\n      <span class=\"font-bold text-base\">{Astro.props.name}</span>\n    </div>\n  )\n}\n"
  },
  {
    "path": "src/const.ts",
    "content": "export const DICTIONARY_TYPE = {\n  AVAILABILITY: 'availability',\n  CANDIDATE_EXPERIENCE: 'candidate-experience',\n  CANDIDATE_SUBSEGMENT: 'candidate-subsegment',\n  CATEGORY: 'category',\n  CHANNEL: 'channel',\n  CITY: 'city',\n  CONTRACT_TYPE: 'contract-type',\n  COUNTRY: 'country',\n  DRIVER_LICENSE: 'driver-license',\n  EMPLOYMENT_STATUS: 'employment-status',\n  EMPLOYER_TYPE: 'employer-type',\n  EXPERIENCE_MIN: 'experience-min',\n  GENDER: 'gender',\n  GRADE: 'grade',\n  ID_TYPE: 'id-type',\n  INDUSTRY: 'industry',\n  LANGUAGE: 'language',\n  LAST_JOB_SEARCH: 'last-job-search',\n  LEGAL_FORM: 'legal-form',\n  MANAGER_PROFESSIONAL_LEVEL: 'manager-professional-level',\n  MANDATORY_STEPS: 'mandatory-steps',\n  OFFER_RESIDENCE: 'offer-residence',\n  OFFER_STATE: 'offer-state',\n  PERIODOS_INTERVALOS: 'periodos-intervalos',\n  PROFESSIONAL_LEVEL: 'professional-level',\n  PROVINCE: 'province',\n  READING_LEVEL: 'reading-level',\n  REGION: 'region',\n  REPORT_REASONS: 'report-reason',\n  REPORTING_TO: 'reporting-to',\n  SALARY_BENEFITS: 'salary-benefits',\n  SALARY_PERIOD: 'salary-period',\n  SALARY_RANGE: 'salary-range',\n  STUDY: 'study',\n  SKILL_LEVEL: 'skill-level',\n  SPEAKING_LEVEL: 'speaking-level',\n  STAFF: 'staff',\n  STUDY_DETAIL: 'study-detail',\n  SUBCATEGORY: 'subcategory',\n  TELEWORKING: 'teleworking',\n  TIMELINE_EVENT: 'timeline-event',\n  URL_TYPE: 'url-type',\n  WORK_PERMIT: 'work-permit',\n  WORKDAY: 'workday',\n  WRITING_LEVEL: 'writing-level'\n} as const\n"
  },
  {
    "path": "src/env.d.ts",
    "content": "/// <reference path=\"../.astro/types.d.ts\" />"
  },
  {
    "path": "src/icons/AppStore.astro",
    "content": "<img\n  src=\"/footer-app-store.webp\"\n  alt=\"Logo App Store\"\n  class=\"h-[50px] w-auto\"\n/>\n"
  },
  {
    "path": "src/icons/ChevronDown.astro",
    "content": "---\nconst { ...props } = Astro.props\n---\n\n<svg \n    xmlns=\"http://www.w3.org/2000/svg\" \n    viewBox=\"0 0 24 24\" \n    class={'stroke-gray-600 transition-transform duration-300 ease-in-out'} \n    {...props}\n>\n\t<path d=\"m5.84 9.59l5.66 5.66l5.66-5.66l-.71-.7l-4.95 4.95l-4.95-4.95z\" />\n</svg>\n"
  },
  {
    "path": "src/icons/CloseIcon.astro",
    "content": "<svg width=\"14\" height=\"14\" fill=\"none\"\n  ><path\n    fill=\"#89898A\"\n    fill-rule=\"evenodd\"\n    d=\"m8.47 6.95 4.79-4.8A1 1 0 0 0 11.85.74l-4.8 4.79L2.26.74A1 1 0 0 0 .85 2.15l4.79 4.8-4.79 4.79a1 1 0 1 0 1.41 1.41l4.79-4.79 4.8 4.79a1 1 0 0 0 1.41-1.41L8.47 6.95Z\"\n    clip-rule=\"evenodd\"></path></svg\n>\n"
  },
  {
    "path": "src/icons/Facebook.astro",
    "content": "<svg width=\"22\" height=\"22\" fill=\"none\">\n  <path\n    fill=\"currentColor\"\n    fill-rule=\"evenodd\"\n    d=\"M11 .75C5.34.75.75 5.34.75 11S5.34 21.25 11 21.25 21.25 16.66 21.25 11C21.244 5.341 16.659.756 11 .75ZM19.75 11A8.75 8.75 0 1 1 11 2.25 8.76 8.76 0 0 1 19.75 11Zm-8.106 5.75v-5.474h1.77l.264-2.134h-2.034V7.78c0-.617.166-1.038 1.019-1.038h1.087V4.832a14.299 14.299 0 0 0-1.585-.083c-1.568 0-2.642.993-2.642 2.82v1.572H7.75v2.134h1.773v5.474h2.121Z\"\n    clip-rule=\"evenodd\"\n  >\n  </path>\n</svg>\n"
  },
  {
    "path": "src/icons/GooglePlay.astro",
    "content": "<img\n  src=\"/footer-google-play.webp\"\n  alt=\"Logo Google Play\"\n  class=\"h-[50px] w-auto\"\n/>\n"
  },
  {
    "path": "src/icons/LeftArrow.astro",
    "content": "<svg width=\"32\" height=\"32\" fill=\"none\" viewBox=\"0 0 32 32\" {...Astro.props}>\n  <path\n    fill=\"currentColor\"\n    fill-rule=\"evenodd\"\n    d=\"M19.334 24.667a1.333 1.333 0 0 1-.947-.387l-5.44-5.44a4 4 0 0 1 0-5.653l5.454-5.467a1.333 1.333 0 0 1 1.88 1.88l-5.454 5.467a1.333 1.333 0 0 0 0 1.88l5.44 5.44a1.333 1.333 0 0 1-.947 2.28h.014Z\"\n    clip-rule=\"evenodd\"></path>\n</svg>\n"
  },
  {
    "path": "src/icons/Play.astro",
    "content": "<svg width=\"16\" height=\"18\" viewBox=\"0 0 16 18\" fill=\"none\" {...Astro.props}>\n  <path\n    d=\"M15 7.26795C16.3333 8.03775 16.3333 9.96225 15 10.7321L3 17.6603C1.66667 18.4301 2.92002e-06 17.4678 2.98732e-06 15.9282L3.593e-06 2.0718C3.6603e-06 0.532196 1.66667 -0.430054 3 0.339746L15 7.26795Z\"\n    fill=\"currentColor\"></path>\n</svg>\n"
  },
  {
    "path": "src/icons/RightArrow.astro",
    "content": "<svg width=\"32\" height=\"32\" fill=\"none\" viewBox=\"0 0 32 32\" {...Astro.props}>\n  <path\n    fill=\"currentColor\"\n    fill-rule=\"evenodd\"\n    d=\"M13.105 24.667c.354.002.695-.137.946-.387l5.44-5.44a4 4 0 0 0 0-5.653L14.038 7.72a1.333 1.333 0 0 0-1.88 1.88l5.453 5.467c.517.52.517 1.36 0 1.88l-5.44 5.44a1.333 1.333 0 0 0 .947 2.28h-.013Z\"\n    clip-rule=\"evenodd\"></path>\n</svg>\n"
  },
  {
    "path": "src/icons/Search.astro",
    "content": "<svg width=\"16\" height=\"19\" fill=\"none\" viewBox=\"0 0 19 19\" {...Astro.props}>\n  <path\n    fill=\"currentColor\"\n    fill-rule=\"evenodd\"\n    d=\"m18.21 16.79-5.11-5.11a7 7 0 1 0-1.41 1.41l5.11 5.11a1 1 0 0 0 1.41-1.41ZM2.5 7.5a5 5 0 1 1 10 0 5 5 0 0 1-10 0Z\"\n    clip-rule=\"evenodd\"\n  >\n  </path>\n</svg>\n"
  },
  {
    "path": "src/icons/Spinner.astro",
    "content": "<svg\n  {...Astro.props}\n  xmlns=\"http://www.w3.org/2000/svg\"\n  fill=\"none\"\n  viewBox=\"0 0 24 24\"\n  width=\"24\" height=\"24\"\n>\n    <circle\n        class=\"opacity-25\"\n        cx=\"12\"\n        cy=\"12\"\n        r=\"10\"\n        stroke=\"currentColor\"\n        stroke-width=\"4\">\n    </circle>\n    <path\n        class=\"opacity-75\"\n        fill=\"currentColor\"\n        d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\" >\n    </path>\n</svg>\n"
  },
  {
    "path": "src/icons/TikTok.astro",
    "content": "<svg width=\"24\" height=\"24\" fill=\"none\">\n  <path\n    fill=\"currentColor\"\n    fill-rule=\"evenodd\"\n    d=\"M22.25 12C22.244 6.341 17.659 1.756 12 1.75 6.34 1.75 1.75 6.34 1.75 12S6.34 22.25 12 22.25 22.25 17.66 22.25 12Zm-19 0A8.75 8.75 0 0 1 12 3.25 8.76 8.76 0 0 1 20.75 12a8.75 8.75 0 1 1-17.5 0Z\"\n    clip-rule=\"evenodd\"\n  >\n  </path>\n  <path\n    fill=\"currentColor\"\n    stroke=\"currentColor\"\n    stroke-width=\".35\"\n    d=\"M17.79 9.172A3.199 3.199 0 0 1 14.587 6h-2.069v5.651l-.002 3.096a1.872 1.872 0 0 1-1.981 1.868 1.864 1.864 0 0 1-.856-.263 1.872 1.872 0 0 1-.915-1.577 1.874 1.874 0 0 1 2.466-1.805v-2.099a4.07 4.07 0 0 0-.597-.045 3.966 3.966 0 0 0-2.98 1.333 3.88 3.88 0 0 0-.978 2.34 3.875 3.875 0 0 0 1.154 3.02 3.966 3.966 0 0 0 2.805 1.148 3.953 3.953 0 0 0 2.805-1.148 3.872 3.872 0 0 0 1.16-2.756l-.01-4.623a5.225 5.225 0 0 0 3.207 1.09V9.171h-.006Z\"\n  >\n  </path>\n</svg>\n"
  },
  {
    "path": "src/icons/Twitter.astro",
    "content": "<svg width=\"22\" height=\"22\" fill=\"none\">\n  <path\n    fill=\"currentColor\"\n    fill-rule=\"evenodd\"\n    d=\"m15.573 6-3.642 4.234L15.892 16H12.98l-2.668-3.883L6.97 16h-.864l3.82-4.44L6.108 6h2.914l2.526 3.677L14.71 6h.863Zm-2.188 9.38h1.326L8.608 6.65H7.282l6.103 8.73Z\"\n    clip-rule=\"evenodd\"\n  >\n  </path>\n  <path\n    fill=\"currentColor\"\n    fill-rule=\"evenodd\"\n    d=\"M21.25 11C21.244 5.341 16.659.756 11 .75 5.34.75.75 5.34.75 11S5.34 21.25 11 21.25 21.25 16.66 21.25 11Zm-19 0A8.75 8.75 0 0 1 11 2.25 8.76 8.76 0 0 1 19.75 11a8.75 8.75 0 1 1-17.5 0Z\"\n    clip-rule=\"evenodd\"\n  >\n  </path>\n</svg>\n"
  },
  {
    "path": "src/icons/YouTube.astro",
    "content": "<svg width=\"22\" height=\"22\" fill=\"none\">\n  <path\n    fill=\"currentColor\"\n    fill-rule=\"evenodd\"\n    d=\"M11 .75C5.34.75.75 5.34.75 11S5.34 21.25 11 21.25 21.25 16.66 21.25 11C21.244 5.341 16.659.756 11 .75ZM19.75 11A8.75 8.75 0 1 1 11 2.25 8.76 8.76 0 0 1 19.75 11Zm-3-3a1.469 1.469 0 0 0-1.062-1.011C14.752 6.75 11 6.75 11 6.75s-3.753 0-4.688.239a1.469 1.469 0 0 0-1.061 1.01C5 8.89 5 10.75 5 10.75s0 1.86.25 2.75c.139.492.545.88 1.062 1.011.935.239 4.688.239 4.688.239s3.752 0 4.688-.239a1.469 1.469 0 0 0 1.061-1.01C17 12.61 17 10.75 17 10.75s0-1.86-.25-2.75Zm-7 4.75 3-2-3-2v4Z\"\n    clip-rule=\"evenodd\"\n  >\n  </path>\n</svg>\n"
  },
  {
    "path": "src/layouts/Layout.astro",
    "content": "---\nimport Header from \"../components/Header.astro\"\nimport Footer from \"../components/Footer.astro\"\n\ninterface Props {\n  title: string\n}\n\nconst { title } = Astro.props\n---\n\n<!doctype html>\n<html lang=\"es\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>{title}</title>\n    <meta\n      name=\"description\"\n      content=\"Usa InfoJobs e impulsa tu carrera trabajando en una empresa líder\"\n    />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n\n    <meta\n      property=\"twitter:image\"\n      content=\"https://primer-trabajo.infojobs.net/og.jpg\"\n    />\n    <meta property=\"twitter:card\" content=\"summary_large_image\" />\n    <meta\n      property=\"twitter:title\"\n      content=\"Encuentra tu Primer Trabajo en InfoJobs\"\n    />\n    <meta\n      property=\"twitter:description\"\n      content=\"Usa InfoJobs e impulsa tu carrera trabajando en una empresa líder\"\n    />\n\n    <meta\n      property=\"og:image\"\n      content=\"https://primer-trabajo.infojobs.net/og.jpg\"\n    />\n    <meta property=\"og:site_name\" content=\"InfoJobs.net\" />\n    <meta property=\"og:title\" content={title} />\n    <meta\n      property=\"og:description\"\n      content=\"Usa InfoJobs e impulsa tu carrera trabajando en una empresa líder\"\n    />\n    <meta property=\"og:url\" content=\"https://primer-trabajo.infojobs.net/\" />\n\n    <link rel=\"preload\" as=\"image\" href=\"/hero-pattern.webp\" />\n    <script is:inline>\n      !(function () {\n        try {\n          !(function () {\n            var a = \"__tcfapi\",\n              t = a + \"Locator\"\n            if (!window.frames[t]) {\n              var n = window,\n                e = n.document,\n                r = 999,\n                c = setInterval(function () {\n                  if (e.body || 0 === r) {\n                    clearInterval(c)\n                    var a = e.createElement(\"iframe\")\n                    ;(a.style.display = \"none\"),\n                      (a.name = t),\n                      e.body.appendChild(a)\n                  }\n                  r -= 1\n                }, 5)\n              n.addEventListener(\n                \"message\",\n                function (t) {\n                  if (null != t && t.data) {\n                    var e\n                    try {\n                      e =\n                        \"string\" == typeof t.data ? JSON.parse(t.data) : t.data\n                    } catch (a) {}\n                    var r = e && e.__tcfapiCall\n                    r &&\n                      n[a](\n                        r.command,\n                        r.version,\n                        function (a, n) {\n                          var e,\n                            c =\n                              (((e = {}).__tcfapiReturn = {\n                                returnValue: a,\n                                success: n,\n                                callId: r.callId,\n                              }),\n                              e)\n                          t.source.postMessage(c, \"*\")\n                        },\n                        r.parameter\n                      )\n                  }\n                },\n                !1\n              ),\n                (n[a] = function (t, e, r, c) {\n                  \"ping\" === t && r\n                    ? r({ gdprApplies: !0, cmpLoaded: !1, cmpStatus: \"stub\" })\n                    : n[a].Q.push(function () {\n                        return n[a](t, e, r, c)\n                      })\n                }),\n                (n[a].Q = []),\n                (n.__borosTcf = {\n                  push: function (t) {\n                    return n[a](t)\n                  },\n                })\n            }\n          })()\n        } catch (a) {}\n      })()\n    </script>\n\n    <script is:inline>\n      !(function () {\n        var analytics = (window.analytics = window.analytics || [])\n        if (!analytics.initialize)\n          if (analytics.invoked)\n            window.console &&\n              console.error &&\n              console.error(\"Segment snippet included twice.\")\n          else {\n            analytics.invoked = !0\n            analytics.methods = [\n              \"trackSubmit\",\n              \"trackClick\",\n              \"trackLink\",\n              \"trackForm\",\n              \"pageview\",\n              \"identify\",\n              \"reset\",\n              \"group\",\n              \"track\",\n              \"ready\",\n              \"alias\",\n              \"debug\",\n              \"page\",\n              \"once\",\n              \"off\",\n              \"on\",\n              \"addSourceMiddleware\",\n              \"addIntegrationMiddleware\",\n              \"setAnonymousId\",\n              \"addDestinationMiddleware\",\n            ]\n            analytics.factory = function (e) {\n              return function () {\n                var t = Array.prototype.slice.call(arguments)\n                t.unshift(e)\n                analytics.push(t)\n                return analytics\n              }\n            }\n            for (var e = 0; e < analytics.methods.length; e++) {\n              var key = analytics.methods[e]\n              analytics[key] = analytics.factory(key)\n            }\n            analytics.load = function (key, e) {\n              var t = document.createElement(\"script\")\n              t.type = \"text/javascript\"\n              t.async = !0\n              t.src =\n                \"https://cdn.segment.com/analytics.js/v1/\" +\n                key +\n                \"/analytics.min.js\"\n              var n = document.getElementsByTagName(\"script\")[0]\n              n.parentNode.insertBefore(t, n)\n              analytics._loadOptions = e\n            }\n            analytics.SNIPPET_VERSION = \"4.15.3\"\n            analytics.load(\"I1QsIrOJ5GuAZZFGRCfN8USp89gdFD2u\")\n          }\n      })()\n    </script>\n\n    <script\n      is:inline\n      defer\n      src=\"https://components.infojobs.com/widgets/downloader.js\"></script>\n\n    <script\n      defer\n      is:inline\n      src=\"https://unpkg.com/@s-ui/ij-segment-wrapper@2.6.0/umd/index.js\"\n    ></script>\n    <script is:inline defer>\n      analytics.track(\"Landing Page Viewed\", {\n        page_name: \"landing_midudev_proyecto_jovenes\",\n        site: \"infojobs.net\",\n        section: \"candidate\",\n        channel: \"landing_captacion_ontarget\",\n        platform: \"web\",\n        vertical: \"jobs\",\n        page_type: \"landing\",\n      })\n    </script>\n  </head>\n</html>\n<body>\n  <Header />\n  <main class=\"flex flex-col gap-20 md:gap-24\">\n    <slot />\n  </main>\n  <div id=\"cmpContainer\"></div>\n  <Footer />\n</body>\n\n<script is:inline defer>\n  const DEFAULT_TRACKING = {\n    channel: \"landing_captacion_ontarget\",\n    page_detail: \"landing_midudev_proyecto_jovenes\",\n    platform: \"web\",\n    section: \"candidate\",\n    site: \"infojobs.net\",\n    vertical: \"jobs\",\n  }\n\n  const elementsToTrack = document.querySelectorAll(\"[data-track]\")\n\n  elementsToTrack.forEach((el) => {\n    el.addEventListener(\"click\", (event) => {\n      const { track } = event.currentTarget.dataset\n      const trackingData = { ...DEFAULT_TRACKING, label: track }\n      window.analytics.track(\"Button Clicked\", trackingData)\n    })\n  })\n</script>\n\n<style is:global>\n  input:focus-visible,\n  select:focus-visible {\n    outline: 0;\n  }\n\n  html {\n    scroll-behavior: smooth;\n  }\n</style>\n"
  },
  {
    "path": "src/lib/generate-infojobs-keywords-url.ts",
    "content": "const DEFAULT_SEARCH_URL = \"https://ms-autocomplete.spain.advgo.net/v1/search\"\nconst MAX_RESULTS = \"5\"\n\nexport const generateInfoJobsKeywordsURL = ({ prefix }: { prefix: string }) => {\n    const searchURL = new URL(DEFAULT_SEARCH_URL)\n\n    if (!prefix) return\n\n    searchURL.searchParams.set(\"prefix\", prefix)\n    searchURL.searchParams.set(\"max_results\", MAX_RESULTS)\n\n    return searchURL.toString()\n}"
  },
  {
    "path": "src/lib/generate-infojobs-url.ts",
    "content": "const DEFAULT_SEARCH_URL = \"https://www.infojobs.net/jobsearch/search-results/list.xhtml\"\nconst SPAIN_COUNTRY_ID = \"17\"\nconst FIRST_PAGE = \"1\"\nconst SORT_BY_RELEVANCE = \"RELEVANCE\"\n\nexport const generateInfoJobsURL = ({\n  keyword,\n  level,\n  provinceIds\n}: {\n  keyword: string,\n  level: string,\n  provinceIds: string\n}) => {\n  const searchURL = new URL(DEFAULT_SEARCH_URL)\n  \n  if (keyword) searchURL.searchParams.set(\"keyword\", keyword)\n  if (level) searchURL.searchParams.set(\"educationIds\", level)\n  \n  if (provinceIds) searchURL.searchParams.set(\"provinceIds\", provinceIds)\n  else searchURL.searchParams.set(\"countryIds\", SPAIN_COUNTRY_ID)\n\n  searchURL.searchParams.set(\"page\", FIRST_PAGE)\n  searchURL.searchParams.set(\"sortBy\", SORT_BY_RELEVANCE)\n  \n  return searchURL.toString()\n}"
  },
  {
    "path": "src/lib/get-ij-studies.ts",
    "content": "import { getDictionary } from '@lib/query'\n \nexport const getStudies = () => {\n  return getDictionary('study')\n}"
  },
  {
    "path": "src/lib/list-provinces-ids.ts",
    "content": "const listProvincesIds = {\n  'Otro país': 1,\n  'Álava/Araba': 2,\n  Albacete: 3,\n  'Alicante/Alacant': 4,\n  Almería: 5,\n  Asturias: 6,\n  Ávila: 7,\n  Badajoz: 8,\n  Barcelona: 9,\n  Burgos: 10,\n  Cáceres: 11,\n  Cádiz: 12,\n  Cantabria: 13,\n  'Castellón/Castelló': 14,\n  Ceuta: 15,\n  'Ciudad Real': 16,\n  Córdoba: 17,\n  Cuenca: 18,\n  Girona: 19,\n  'Las Palmas': 20,\n  Granada: 21,\n  Guadalajara: 22,\n  'Guipúzcoa/Gipuzkoa': 23,\n  Huelva: 24,\n  Huesca: 25,\n  'Islas Baleares/Illes Balears': 26,\n  Jaén: 27,\n  'A Coruña': 28,\n  'La Rioja': 29,\n  León: 30,\n  Lleida: 31,\n  Lugo: 32,\n  Madrid: 33,\n  Málaga: 34,\n  Melilla: 35,\n  Murcia: 36,\n  Navarra: 37,\n  Ourense: 38,\n  Palencia: 39,\n  Pontevedra: 40,\n  Salamanca: 41,\n  Segovia: 42,\n  Sevilla: 43,\n  Soria: 44,\n  Tarragona: 45,\n  'Santa Cruz de Tenerife': 46,\n  Teruel: 47,\n  Toledo: 48,\n  'Valencia/València': 49,\n  Valladolid: 50,\n  'Vizcaya/Bizkaia': 51,\n  Zamora: 52,\n  Zaragoza: 53,\n}\n\nexport function getProvinceId(input: HTMLInputElement): void {\n  const provinceId = listProvincesIds[input.value as keyof typeof listProvincesIds]\n  input.setAttribute(\"value\", provinceId !== undefined ? provinceId.toString() : \"0\")\n\n  if (!provinceId) input.setAttribute(\"value\", \"0\")\n}"
  },
  {
    "path": "src/lib/mocks.ts",
    "content": "export const dictionaries: Record<string, { id: number, value: string, order: number, key: string }[]> = {\n  'study': [\n    { id: 0, value: '(Indicar Nivel)', order: 0, key: 'indicar-nivel' },\n    { id: 10, value: 'Sin estudios', order: 5, key: 'sin-estudios' },\n    {\n      id: 20,\n      value: 'Educación Secundaria Obligatoria',\n      order: 10,\n      key: 'educacion-secundaria-obligatoria'\n    },\n    { id: 50, value: 'Bachillerato', order: 20, key: 'bachillerato' },\n    {\n      id: 35,\n      value: 'Ciclo Formativo Grado Medio',\n      order: 30,\n      key: 'ciclo-formativo-grado-medio'\n    },\n    {\n      id: 60,\n      value: 'Ciclo Formativo Grado Superior',\n      order: 40,\n      key: 'ciclo-formativo-grado-superior'\n    },\n    {\n      id: 23,\n      value: 'Enseñanzas artísticas (regladas)',\n      order: 50,\n      key: 'ensenanzas-artisticas-regladas'\n    },\n    {\n      id: 27,\n      value: 'Enseñanzas deportivas (regladas)',\n      order: 60,\n      key: 'ensenanzas-deportivas-regladas'\n    },\n    { id: 125, value: 'Grado', order: 70, key: 'grado' },\n    { id: 140, value: 'Licenciatura', order: 80, key: 'licenciado' },\n    { id: 110, value: 'Diplomatura', order: 90, key: 'diplomado' },\n    {\n      id: 120,\n      value: 'Ingeniería Técnica',\n      order: 100,\n      key: 'ingeniero-tecnico'\n    },\n    {\n      id: 130,\n      value: 'Ingeniería Superior',\n      order: 110,\n      key: 'ingeniero-superior'\n    },\n    { id: 143, value: 'Postgrado', order: 120, key: 'postgrado' },\n    { id: 147, value: 'Máster', order: 130, key: 'master' },\n    { id: 150, value: 'Doctorado', order: 140, key: 'doctorado' },\n    {\n      id: 160,\n      value: 'Otros títulos, certificaciones y carnés',\n      order: 150,\n      key: 'otros-titulos-certificaciones-y-carnes'\n    },\n    {\n      id: 170,\n      value: 'Otros cursos y formación no reglada',\n      order: 160,\n      key: 'otros-cursos-y-formacion-no-reglada'\n    },\n    {\n      id: 30,\n      value: 'Formación Profesional Grado Medio',\n      order: 170,\n      key: 'formacion-profesional-grado-medio'\n    },\n    {\n      id: 55,\n      value: 'Formación Profesional Grado Superior',\n      order: 180,\n      key: 'formacion-profesional-grado-superior'\n    }\n  ]\n}"
  },
  {
    "path": "src/lib/query.ts",
    "content": "import type { DictionaryId } from \"../types.ts\"\nimport { dictionaries } from \"./mocks.ts\"\n\nconst INFOJOBS_API_ENDPOINT = \"https://api.infojobs.net/api/1/\"\n\nconst TOKEN = import.meta.env.API_INFOJOBS_TOKEN\n\nexport const query = async (path: string) => {\n  const url = `${INFOJOBS_API_ENDPOINT}${path}`\n  return fetch(url, {\n    headers: {\n      Authorization: `Basic ${TOKEN}`,\n      'Content-Type': 'application/json',\n    }\n  }).then(res => res.json())\n}\n\nexport const getDictionary = (dictionaryId: DictionaryId): Promise<Array<{ id: number, value: string, order: number, key: string }>> => {\n  if (!TOKEN) return Promise.resolve(dictionaries[dictionaryId])\n  return query(`/dictionary/${dictionaryId}`)\n}\n"
  },
  {
    "path": "src/lib/queryKeywords.ts",
    "content": "import { generateInfoJobsKeywordsURL } from \"./generate-infojobs-keywords-url\";\n\nexport const queryKeywords = async (prefix: string) => {\n  const url = generateInfoJobsKeywordsURL({ prefix });\n\n  if (!url) return;\n\n  return fetch(url, {\n    headers: {\n      \"Content-Type\": \"application/json\",\n    },\n  }).then((res) => res.json());\n};\n"
  },
  {
    "path": "src/pages/index.astro",
    "content": "---\nimport BentoInfo from \"@components/BentoInfo.astro\";\nimport CoolJobs from \"@components/CoolJobs.astro\";\nimport HeroSearch from \"@components/HeroSearch.astro\";\nimport SocialBest from \"@components/SocialBest.astro\";\nimport PreFooter from \"@components/PreFooter.astro\";\nimport InfographicModal from \"@components/InfographicModal.astro\";\nimport StandsInterviews from \"@components/StandsInterviews.astro\";\n\nimport Layout from \"@layouts/Layout.astro\";\n\nimport EmergentPositions from \"@components/EmergentPositions.astro\";\n\nimport YourNextJob from \"@components/YourNextJob.astro\";\n\n---\n\n<Layout title=\"InfoJobs - ¡Encuentra tu primer empleo!\">\n  <HeroSearch />\n  <BentoInfo />\n  <SocialBest />\n  <CoolJobs />\n  <PreFooter />\n  <InfographicModal />\n\n  <!-- Infografías -->\n  <StandsInterviews infographicId=\"no-experience\" />\n\n  <EmergentPositions infographicId=\"emergent-positions\" />\n\n  <YourNextJob infographicId=\"selection-process\" />\n\n</Layout>\n"
  },
  {
    "path": "src/types.ts",
    "content": "import { DICTIONARY_TYPE } from \"./const\"\n\nexport type DictionaryId = (typeof DICTIONARY_TYPE)[keyof typeof DICTIONARY_TYPE]\n\nexport type CoolJobs = { image: string; title: string; brand: string; section_id: string; }\n"
  },
  {
    "path": "tailwind.config.mjs",
    "content": "/** @type {import('tailwindcss').Config} */\nexport default {\n  content: [\"./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}\"],\n  theme: {\n    extend: {\n      colors: {\n        primary: \"#167DB7\",\n        accent: \"#FE5230\",\n        \"ij-black\": \"#212121\",\n        \"ij-red\": \"#FF421C\",\n        \"ij-green\": \"#00A550\",\n        \"ij-blue\": \"#E8F2F8\",\n        \"ij-yellow\": \"#EFA500\",\n      },\n      backgroundImage: {\n        \"hero-pattern\": \"url(/hero-pattern.webp)\",\n      },\n      borderRadius: {\n        \"4xl\": \"3rem\",\n      },\n      backgroundSize: {\n        \"auto-height\": \"auto 100%\",\n      },\n      letterSpacing: {\n        separated: \"0.35px\",\n      },\n      padding: {\n        15: \"60px\",\n      },\n      transitionDuration: {\n        DEFAULT: \"500ms\",\n      },\n      screens: {\n        xs: \"480px\",\n      },\n    },\n  },\n  plugins: [\n    ({ addUtilities }) => {\n      const newUtilities = {\n        \".no-scrollbar::-webkit-scrollbar\": {\n          display: \"none\",\n        },\n        \".no-scrollbar\": {\n          \"-ms-overflow-style\": \"none\",\n          \"scrollbar-width\": \"none\",\n        },\n      };\n\n      addUtilities(newUtilities);\n    },\n  ],\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"extends\": \"astro/tsconfigs/strict\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"paths\": {\n      \"@components/*\": [\n        \"src/components/*\"\n      ],\n      \"@ui/*\": [\n        \"src/components/ui/*\"\n      ],\n      \"@layouts/*\": [\n        \"src/layouts/*\"\n      ],\n      \"@icons/*\": [\n        \"src/icons/*\"\n      ],\n      \"@lib/*\": [\n        \"src/lib/*\"\n      ],\n      \"@types\": [\n        \"src/types.ts\"\n      ]\n    }\n  }\n}"
  }
]