:root {
    --bs-body-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --bs-body-bg: #f7f7fb;
    --bs-body-color: #262a35;
    --bs-primary: #4f56d3;
    --bs-primary-rgb: 79, 86, 211;
    --bs-link-color: #4f56d3;
    --bs-link-color-rgb: 79, 86, 211;
    --bs-link-hover-color: #3c42a8;
    --bs-link-hover-color-rgb: 60, 66, 168;
    --bs-border-color: #e7e7f1;
    --bs-border-radius: 0.6rem;
    --bs-border-radius-sm: 0.45rem;
    --bs-border-radius-lg: 0.9rem;
    --accent-gradient: linear-gradient(135deg, #4f56d3, #7c6ff0);
    --container-app-width: 920px;
    --container-admin-form-width: 480px;
}

.container-app {
    max-width: var(--container-app-width);
}

.container-admin-form {
    max-width: var(--container-admin-form-width);
}

html {
    background: radial-gradient(circle at top left, rgba(79, 86, 211, 0.08), transparent 50%);
    background-attachment: fixed;
}

body {
    letter-spacing: -0.01em;
    background: transparent;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

h1, h2, h3, h4, h5, h6 {
    font-weight: 600;
    letter-spacing: -0.02em;
}

a {
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

.btn {
    font-weight: 500;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.btn:hover {
    transform: translateY(-1px);
}

/* Buttons welded into a group (e.g. radio btn-group toggles) must stay flat:
   lifting a single segment on hover shifts it out of line and breaks the row. */
.btn-group .btn:hover,
.btn-group-vertical .btn:hover {
    transform: none;
}

.btn-primary {
    --bs-btn-bg: var(--bs-primary);
    --bs-btn-border-color: var(--bs-primary);
    --bs-btn-hover-bg: #3c42a8;
    --bs-btn-hover-border-color: #3c42a8;
    --bs-btn-active-bg: #3c42a8;
    --bs-btn-active-border-color: #3c42a8;
    box-shadow: 0 6px 16px rgba(79, 86, 211, 0.25);
}

.btn-primary:hover {
    box-shadow: 0 8px 20px rgba(79, 86, 211, 0.32);
}

.spin-slow {
    display: inline-block;       /* needed so transform applies cleanly */
    animation: spin 20s linear infinite;
}

/* Item de menu correspondant à la page courante : trait rouge (2px) sous le
   libellé. Pattern générique pour tous les items de la navbar. */
.navbar-nav .nav-link.active {
    text-decoration: underline;
    text-decoration-color: var(--bs-danger);
    text-decoration-thickness: 2px;
    text-underline-offset: 6px;
}

/* Badge « Admin » : marque une action réservée aux admins mais rendue côté
   front (page publique). Accent violet, volontairement distinct du primaire
   (indigo) et du danger (rouge) pour ne pas être confondu avec une action
   destructrice. Voir le partial @Shared/_admin_badge.html.twig.
   NB : le badge reste un inline-block (jamais dans un conteneur flex), pour
   qu'il échappe naturellement au soulignement au survol du lien parent —
   text-decoration:none ne sort pas un flex item d'un underline propagé. */
.badge-admin {
    background-color: #ede9fb;
    color: #4c3aa8;
    font-weight: 500;
}
.btn .badge-admin {
    top: 0
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

.card {
    border-color: var(--bs-border-color);
    border-radius: 1rem;
    box-shadow: 0 10px 30px rgba(20, 20, 43, 0.06);
    background-color: #fff;
    background-image: linear-gradient(180deg, #ffffff 0%, #f8f8fc 100%);
}

/* Tableaux logés dans une carte : la table colle aux bords. Pas d'overflow:hidden
   sur la carte (sinon les menus déroulants des cellules seraient rognés) — on
   arrondit donc à la main les cellules du bas et on retire leur bordure pour
   épouser le radius de la carte. Le haut (thead transparent) épouse déjà le radius. */
.card > .table,
.card > .table-responsive > .table {
    margin-bottom: 0;
}

.card > .table > tbody > tr:last-child > td,
.card > .table-responsive > .table > tbody > tr:last-child > td {
    border-bottom: 0;
}

.card > .table > tbody > tr:last-child > td:first-child,
.card > .table-responsive > .table > tbody > tr:last-child > td:first-child {
    border-bottom-left-radius: 1rem;
}

.card > .table > tbody > tr:last-child > td:last-child,
.card > .table-responsive > .table > tbody > tr:last-child > td:last-child {
    border-bottom-right-radius: 1rem;
}

.table > thead th {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-weight: 600;
    color: var(--bs-secondary-color);
    text-align: center;
}

/* Éloigne la 1re/dernière colonne du bord arrondi de la carte. */
.card .table > :not(caption) > * > *:first-child {
    padding-left: 0.25rem;
}

.card .table > :not(caption) > * > *:last-child {
    padding-right: 0.25rem;
}

.form-control, .form-select {
    border-color: var(--bs-border-color);
    padding-top: 0.55rem;
    padding-bottom: 0.55rem;
}

.form-control:focus, .form-select:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 0.2rem rgba(79, 86, 211, 0.15);
}

.js-autosize-textarea {
    resize: none;
    overflow-y: hidden;
}

/* Rendered Markdown (terms of use, privacy policy): scaled down so a
   heading in the source content doesn't dwarf the compact card it sits in. */
.js-markdown-content {
    font-size: 0.875rem;
}

.js-markdown-content h1 {
    font-size: 1.1rem;
}

.js-markdown-content h2 {
    font-size: 1rem;
}

.js-markdown-content h3,
.js-markdown-content h4,
.js-markdown-content h5,
.js-markdown-content h6 {
    font-size: 0.9rem;
}

.navbar {
    box-shadow: 0 1px 0 var(--bs-border-color);
}

.page-header {
    position: relative;
}

/* Le lien de retour est ancré juste au-dessus du titre de page (et non à un
   offset fixe dans la page), pour que le titre garde la même position
   verticale qu'il y ait un retour au-dessus de lui ou non. */
.breadcrumb {
    position: absolute;
    bottom: 100%;
    left: 0;
    margin-bottom: 0.35rem;
}

.dropdown-menu {
    border-color: var(--bs-border-color);
    border-radius: 0.8rem;
    box-shadow: 0 12px 30px rgba(20, 20, 43, 0.12);
    padding: 0.5rem;
}

.dropdown-item {
    border-radius: 0.5rem;
    padding: 0.5rem 0.75rem;
}

/* Dropdown items that open a dialog are anchors without an href (e.g. the
   participant roster's "resend questionnaire" action). Keep them behaving like
   the other link items: pointer cursor, and the shared a:hover underline. */
a.dropdown-item[role="button"] {
    cursor: pointer;
}

.dropdown-header {
    padding: 0.5rem 0.75rem;
}

.avatar-gradient {
    background: var(--accent-gradient);
}

/* Profile photo: a fixed-size circular avatar. Clicking (or tapping) the avatar
   itself opens the file picker to change it -- signalled by the camera badge --
   and the remove link sits below it. No hover-only affordance, so touch and
   desktop behave the same. */
.avatar-photo {
    width: 140px;
    height: 140px;
    font-size: 2.75rem;
}

.avatar-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.avatar-photo-label {
    cursor: pointer;
}

/* Small camera badge over the avatar's corner: the always-visible affordance
   that the avatar itself is clickable to change the photo. */
.avatar-photo-badge {
    position: absolute;
    right: 2px;
    bottom: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background-color: var(--bs-primary, #4c34c6);
    color: #fff;
    border: 2px solid var(--bs-body-bg, #fff);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

/* Keeps the crop area a sensible height whatever the source image ratio, so
   the modal never grows taller than the viewport (Cropper.js sizes to it). */
.avatar-cropper-frame {
    max-height: 60vh;
    overflow: hidden;
}

.avatar-cropper-frame img {
    max-width: 100%;
}

.alert {
    border: none;
}

.js-toast-slide-in {
    animation: toast-slide-in 0.3s ease-out;
}

@keyframes toast-slide-in {
    from {
        transform: translateX(100%);
        opacity: 0;
    }
    to {
        transform: translateX(0);
        opacity: 1;
    }
}

@property --construction-angle {
    syntax: '<angle>';
    inherits: false;
    initial-value: 0deg;
}

.construction-frame {
    position: relative;
    border-radius: 1rem;
    padding: 2px;
}

.construction-frame::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 6px;
    background: conic-gradient(
        from var(--construction-angle),
        #f5c518 0deg 30deg, #1a1a1a 30deg 60deg,
        #f5c518 60deg 90deg, #1a1a1a 90deg 120deg,
        #f5c518 120deg 150deg, #1a1a1a 150deg 180deg,
        #f5c518 180deg 210deg, #1a1a1a 210deg 240deg,
        #f5c518 240deg 270deg, #1a1a1a 270deg 300deg,
        #f5c518 300deg 330deg, #1a1a1a 330deg 360deg
    );
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    animation: construction-tape-rotate 50s linear infinite;
    pointer-events: none;
}

@keyframes construction-tape-rotate {
    to {
        --construction-angle: 360deg;
    }
}

.event-banner {
    background-size: cover;
    background-position: center;
    color: #fff;
    padding: 2.5rem 0;
}

.event-banner-eyebrow {
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.8rem;
    font-weight: 600;
    opacity: 0.85;
}

.event-banner-title {
    font-size: clamp(1.5rem, 4vw, 2.5rem);
}

/* Event subscription card (templates/events/_subscription_card.html.twig):
   a banner-topped card used in the my-subscriptions / consulted lists. The
   whole card is clickable via the title's stretched-link. */
.event-subscription-card {
    overflow: hidden;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.event-subscription-card:hover,
.event-subscription-card:focus-within {
    border-color: var(--bs-primary);
    box-shadow: 0 10px 30px rgba(var(--bs-primary-rgb), 0.12);
    transform: translateY(-2px);
}

.event-subscription-card-media {
    position: relative;
    min-height: 120px;
    background-color: #14142b;
    background-image: linear-gradient(120deg, rgba(20, 20, 43, 0.85), rgba(79, 86, 211, 0.85));
    background-size: cover;
    background-position: center;
}

.event-subscription-card-media .badge {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
}

.admin-banner-title {
    font-size: clamp(2rem, 6vw, 4rem);
    font-weight: 700;
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
}

.table-clickable-row {
    cursor: pointer;
}

/* Reusable navigation card (templates/shared/_nav_card.html.twig): a whole-card
   link with a hover affordance (arrow slides in + slight lift) so it reads as
   clickable. */
.nav-card {
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.nav-card:hover,
.nav-card:focus-within {
    border-color: var(--bs-primary);
    box-shadow: 0 10px 30px rgba(var(--bs-primary-rgb), 0.12);
    transform: translateY(-2px);
}

.nav-card-icon {
    font-size: 1.375rem;
    color: var(--bs-primary);
}

.nav-card-arrow {
    position: absolute;
    top: 1rem;
    right: 1rem;
    color: var(--bs-primary);
    opacity: 0;
    transform: translateX(-4px);
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.nav-card:hover .nav-card-arrow,
.nav-card:focus-within .nav-card-arrow {
    opacity: 1;
    transform: translateX(0);
}

.event-countdown-segment {
    min-width: 3.5rem;
}

.event-countdown-value {
    font-size: clamp(1.5rem, 3vw, 2.25rem);
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.event-countdown-label {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.7rem;
    opacity: 0.8;
}

.event-cta-float {
    position: fixed;
    right: 1.25rem;
    top: 50%;
    transform: translateY(-50%);
    z-index: 1030;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.65rem 1.1rem;
    border-radius: 2rem;
    background: var(--accent-gradient);
    color: #fff;
    font-weight: 600;
    text-decoration: none;
    box-shadow: 0 0.5rem 1.25rem rgba(var(--bs-primary-rgb), 0.35);
    transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.15s ease;
}

.event-cta-float:hover,
.event-cta-float:focus {
    color: #fff;
    transform: translateY(-50%) scale(1.03);
}

.event-cta-float.is-hidden {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

.event-gallery-cta {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.9rem 1.15rem;
    border-radius: var(--bs-border-radius-lg);
    background: var(--accent-gradient);
    color: #fff;
    text-decoration: none;
    box-shadow: 0 8px 20px rgba(var(--bs-primary-rgb), 0.3);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.event-gallery-cta:hover,
.event-gallery-cta:focus {
    color: #fff;
    transform: translateY(-1px);
    box-shadow: 0 10px 24px rgba(var(--bs-primary-rgb), 0.38);
}

.event-gallery-cta-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.2);
    font-size: 1.1rem;
}

.event-gallery-cta-badge {
    flex-shrink: 0;
    padding: 0.2rem 0.65rem;
    border-radius: 2rem;
    background: rgba(255, 255, 255, 0.22);
    font-size: 0.75rem;
    font-weight: 600;
}

/* Clickable "My questionnaire" card (icon left, title, arrow right). A neutral
   card so it reads distinctly from the accent-gradient gallery CTA above it. */
.event-questionnaire-cta {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.9rem 1.15rem;
    border-radius: var(--bs-border-radius-lg);
    background: #fff;
    border: 1px solid var(--bs-border-color);
    color: var(--bs-body-color);
    text-decoration: none;
    box-shadow: var(--bs-box-shadow-sm);
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.event-questionnaire-cta:hover,
.event-questionnaire-cta:focus {
    color: var(--bs-body-color);
    transform: translateY(-1px);
    border-color: var(--bs-primary);
    box-shadow: 0 8px 20px rgba(var(--bs-primary-rgb), 0.15);
}

.event-questionnaire-cta-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    border-radius: 50%;
    background: rgba(var(--bs-primary-rgb), 0.12);
    color: var(--bs-primary);
    font-size: 1.1rem;
}

/* Placeholder swapped in by image-fallback.js when an <img> fails to load
   (its src becomes a transparent pixel, so all visible content here is CSS).
   The icon is a fixed-size background-image, not the <img> content itself,
   so it always renders at 48x48 centered -- independent of the box's own
   size, whether that's a small thumbnail or a full-width banner. */
img.img-broken {
    background-color: #ced4da;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath fill='%23fff' d='M12 10a2 2 0 0 0-2 2v24a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V12a2 2 0 0 0-2-2H12zm0 2h24v16.17l-6.29-6.29a1 1 0 0 0-1.42 0L22 28.17l-3.29-3.29a1 1 0 0 0-1.42 0L12 30.17V12zm0 21.17 5.29-5.29a1 1 0 0 1 1.09-.22l.13.22 3.29 3.29 6.29-6.29a1 1 0 0 1 1.09-.22l.13.22L36 31.17V34H12v-.83zM18 15a3 3 0 1 0 0 6 3 3 0 0 0 0-6z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 48px 48px;
    min-width: 48px;
    min-height: 48px;
}

/* Media widget cards (see templates/shared/_media_widget.html.twig and
   public/js/media-upload.js). Each card is a square thumbnail with delete/copy
   actions revealed on hover and an optional usage overlay at the bottom-left. */
.media-card {
    position: relative;
    aspect-ratio: 1 / 1;
    border-radius: 0.5rem;
    overflow: hidden;
    background-color: #e9ecef;
}

.media-card img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.media-card-actions {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    display: flex;
    gap: 0.3rem;
    opacity: 0;
    transition: opacity 0.15s ease;
}

.media-card:hover .media-card-actions,
.media-card:focus-within .media-card-actions {
    opacity: 1;
}

.media-card-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background-color: rgba(255, 255, 255, 0.92);
    color: #212529;
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}

.media-card-action:hover {
    background-color: #fff;
}

.media-card-action--danger:hover {
    background-color: var(--bs-danger, #dc3545);
    color: #fff;
}

.media-card-action:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.media-card-usage {
    position: absolute;
    left: 0.5rem;
    bottom: 0.4rem;
    color: #fff;
    font-size: 0.8rem;
    font-weight: 600;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
    pointer-events: none;
}

.media-card-usage.is-unused {
    font-weight: 400;
    opacity: 0.9;
}

/* One-digit verification-code boxes (challenge_code_widget). The caret is
   hidden and the focused box is highlighted instead, so the active slot reads
   as a selected zone rather than a blinking cursor. */
.otp-input {
    /* Keep every box on a single line: the boxes shrink to fit narrow
       screens rather than wrapping onto a second row. The gap shrinks with
       the viewport so the row always fits, even on the smallest phones. */
    flex-wrap: nowrap;
    gap: clamp(0.25rem, 2vw, 0.5rem) !important;
}

.otp-box {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    max-width: 3rem;
    /* Square-ish even when shrunk on small screens. */
    aspect-ratio: 6 / 7;
    height: auto;
    padding: 0;
    /* Scale the digit down with the box so it never forces an overflow. */
    font-size: clamp(1rem, 5vw, 1.5rem);
    font-weight: 600;
    caret-color: transparent;
}

.otp-box::selection {
    background: transparent;
}

.otp-box:focus {
    background-color: rgba(var(--bs-primary-rgb), 0.08);
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.25);
}

/* Site footer: a dark grey band with muted text, sitting below the content
   (the body is a min-height flex column so it stays at the bottom). */
.app-footer {
    background-color: #2b2f33;
    color: #adb5bd;
}

.app-footer a {
    color: #adb5bd;
    text-decoration: none;
}

.app-footer a:hover {
    color: #f8f9fa;
}

/* Language switcher entries: muted like the rest of the footer, with the
   active locale brought forward. Buttons are styled to match the anchors. */
.app-footer .locale-option {
    color: #adb5bd;
    text-decoration: none;
    line-height: 1;
}

.app-footer .locale-option:hover {
    color: #f8f9fa;
}

.app-footer .locale-option.active {
    color: #fff;
    font-weight: 600;
}

/* Discreet language switcher floating below a centered card on footer-less
   pages (sign-in, landing, blocked). Flags only, dimmed on a light background,
   the active locale brought to full opacity. */
.locale-floating {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 1rem;
}

.locale-floating .locale-option {
    padding: 0;
    line-height: 1;
    opacity: 0.5;
    transition: opacity 0.15s ease;
}

/* Soft shadow behind each flag so it stays visible on light/gradient
   backgrounds (the flags carry no border of their own). */
.locale-floating .locale-option img {
    border-radius: 2px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.locale-floating .locale-option:hover,
.locale-floating .locale-option.active {
    opacity: 1;
}

/* Required-field indicator: the form theme (bootstrap_5_layout) adds a
   "required" class to labels and legends of mandatory fields; render the
   conventional red asterisk after them. Forms where requiredness is obvious
   (auth flows) opt out with the no-required-marker class. */
label.required::after,
legend.required::after {
    content: " *";
    color: var(--bs-danger, #dc3545);
}

.no-required-marker label.required::after,
.no-required-marker legend.required::after {
    content: none;
}

/* intl-tel-input (phone-input.js) wraps the field in an inline-block .iti; make
   it span the full width like every other Bootstrap form control, and keep its
   country dropdown above the modal it may be opened from. */
.iti {
    width: 100%;
}

.iti__dropdown-content {
    z-index: 1100;
}
