/* Blog index and category listing — redesign

   Extracted from the redesign mockup (Blog/index.html) and scoped to the blog: the site
   chrome (navbar, footer, buttons) is deliberately left out — the front already
   owns it, and re-importing it would fight the existing cascade.

   The design tokens are redeclared under .blog-redesign rather than :root so
   they cannot leak into the rest of the site, which runs on its own palette.
*/



@media (max-width: 1024px) {
    .blog-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 768px) {
    .blog-grid { grid-template-columns: 1fr; }
}

@media (max-width: 480px) {
    .filter-row { gap: 6px; }
    .filter-pill { padding: 6px 10px;
                font-size: 0.75rem; }
    .blog-card-body { padding: 10px 16px 16px; }
    .blog-card-header { padding: 16px 16px 0; }
}

.blog-hero::before {
    content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: radial-gradient(ellipse at 50% 0%, rgba(255, 107, 53, 0.08) 0%, transparent 60%);
            pointer-events: none;
}

.blog-hero-badge {
    display: inline-flex;
            align-items: center;
            gap: 8px;
            background: rgba(255, 107, 53, 0.1);
            border: 1px solid rgba(255, 107, 53, 0.25);
            padding: 8px 20px;
            border-radius: 50px;
            color: var(--orange);
            font-size: 0.9rem;
            font-weight: 500;
            margin-bottom: 24px;
            animation: fadeIn 1s ease forwards;
}

.blog-hero h1 {
    font-size: clamp(2.2rem, 5vw, 3.8rem);
            font-weight: 900;
            color: var(--text-dark);
            line-height: 1.1;
            margin-bottom: 16px;
            animation: slideUp 1s ease forwards;
            animation-delay: 0.2s;
            opacity: 0;
}

.blog-hero h1 .highlight {
    background: linear-gradient(135deg, var(--orange), var(--orange-light), #ffaa00, var(--orange));
            background-size: 200% auto;
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            animation: shimmer 3s linear infinite;
}

.blog-hero-subtitle {
    font-size: clamp(1rem, 2vw, 1.15rem);
            color: var(--gray);
            max-width: 600px;
            margin: 0 auto 28px;
            animation: slideUp 1s ease forwards;
            animation-delay: 0.4s;
            opacity: 0;
}

.blog-hero-count {
    display: inline-flex;
            align-items: center;
            gap: 6px;
            background: var(--white);
            padding: 8px 20px;
            border-radius: 50px;
            color: var(--text-dark);
            font-size: 0.88rem;
            font-weight: 600;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
            animation: fadeIn 1.2s ease forwards;
            animation-delay: 0.6s;
            opacity: 0;
}

.blog-hero-count i {
    color: var(--orange);
}

.search-wrapper {
    max-width: 560px;
            margin: 0 auto 24px;
            position: relative;
}

.search-wrapper input {
    width: 100%;
            padding: 14px 20px 14px 48px;
            border: 1px solid rgba(0, 0, 0, 0.1);
            border-radius: 50px;
            font-family: 'Inter', sans-serif;
            font-size: 0.95rem;
            background: var(--gray-light);
            color: var(--text-dark);
            transition: all 0.2s ease;
}

.search-wrapper input::placeholder {
    color: var(--gray);
}

.search-wrapper input:focus {
    outline: none;
            border-color: var(--orange);
            box-shadow: 0 0 0 3px rgba(255, 107, 53, 0.12);
            background: var(--white);
}

.search-wrapper i {
    position: absolute;
            left: 18px;
            top: 50%;
            transform: translateY(-50%);
            color: var(--gray);
            font-size: 0.95rem;
}

.search-wrapper .search-clear {
    position: absolute;
            right: 16px;
            top: 50%;
            transform: translateY(-50%);
            background: none;
            border: none;
            color: var(--gray);
            font-size: 0.9rem;
            cursor: pointer;
            display: none;
            padding: 4px;
}

.search-wrapper .search-clear.visible {
    display: block;
}

.filter-row {
    display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            flex-wrap: wrap;
            padding-bottom: 8px;
}

.filter-pill {
    display: inline-flex;
            align-items: center;
            gap: 6px;
            padding: 7px 14px;
            border-radius: 50px;
            background: var(--gray-light);
            border: 1px solid transparent;
            color: var(--text-dark);
            font-family: 'Inter', sans-serif;
            font-weight: 500;
            font-size: 0.82rem;
            cursor: pointer;
            transition: all 0.3s ease;
}

.filter-pill:hover {
    background: rgba(255, 107, 53, 0.1);
            border-color: rgba(255, 107, 53, 0.25);
            color: var(--orange);
}

.filter-pill.active {
    background: var(--orange);
            color: var(--white);
            border-color: var(--orange);
}

.filter-pill i {
    font-size: 0.75rem;
}

.filter-pill .count {
    font-size: 0.72rem;
            opacity: 0.7;
}

.results-info {
    text-align: center;
            padding: 16px 0 0;
            font-size: 0.88rem;
            color: var(--gray);
}

.results-info strong {
    color: var(--text-dark);
}

.blog-grid {
    display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 20px;
}

.blog-card:hover {
    transform: translateY(-4px);
            box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1);
            border-color: rgba(255, 107, 53, 0.2);
}

.blog-card-image {
    position: relative;
            width: 100%;
            height: 240px;
            overflow: hidden;
            background: var(--gray-light);
            /* It is an <a>, so inline by default — and an inline box ignores
               height. The 240px above was being dropped, the frame collapsed to
               a line box, and each card grew to whatever its image happened to
               be: 373x210 for one, 373x373 for the next, so no two cards in a
               row lined up. */
            display: block;
}

/* Same chain, one level down: <picture> is inline too, so `height: 100%` on the
   image below resolved against nothing and it fell back to its intrinsic size.
   Both links have to be blocks for the frame to mean anything. */
.blog-card-image picture {
    display: block;
    height: 100%;
}

.blog-card-image img {
    width: 100%;
            height: 100%;
            object-fit: cover;
            object-position: center;
            transition: transform 0.5s ease;
}

.blog-card:hover .blog-card-image img {
    transform: scale(1.05);
}

.blog-card-image .blog-card-category-badge {
    position: absolute;
            top: 12px;
            left: 12px;
            padding: 4px 12px;
            border-radius: 50px;
            font-size: 0.72rem;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            color: var(--white);
            background: var(--orange);
}

.blog-card-image-placeholder {
    width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            gap: 8px;
            background: var(--gray-light);
}

.blog-card-image-placeholder i {
    font-size: 2rem;
            opacity: 0.25;
            color: var(--text-dark);
}

.blog-card-header {
    display: flex;
            align-items: center;
            gap: 10px;
            padding: 16px 20px 0;
}

.blog-card-icon {
    width: 32px;
            height: 32px;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.85rem;
            flex-shrink: 0;
}

.blog-card-category-label {
    font-size: 0.75rem;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.5px;
}

.blog-card-body {
    padding: 10px 20px 20px;
            display: flex;
            flex-direction: column;
            flex: 1;
}

.blog-card-title {
    font-size: 1rem;
            font-weight: 700;
            color: var(--text-dark);
            line-height: 1.4;
            margin-bottom: 16px;
            flex: 1;
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
            overflow: hidden;
}

.blog-card-title a {
    transition: color 0.2s ease;
}

.blog-card-title a:hover {
    color: var(--orange);
}

.blog-card-footer {
    display: flex;
            align-items: center;
            justify-content: space-between;
            padding-top: 12px;
            border-top: 1px solid var(--gray-light);
}

.blog-card-author {
    /* 0.78rem in the mockup: legible in a wide three-column grid, too small on
       a phone where this line is the card's only meta. */
    font-size: 0.9rem;
            color: var(--gray);
            display: flex;
            align-items: center;
            gap: 4px;
}

/* .vd-icon, not the mockup's `i`: the front's icons are inline SVG, so the
   rule as extracted matched nothing that is ever rendered. */
.blog-card-author .vd-icon {
    color: var(--orange);
    flex-shrink: 0;
}

.blog-card-read {
    display: inline-flex;
            align-items: center;
            gap: 5px;
            color: var(--orange);
            /* Matches .blog-card-author, so the two ends of the footer read as
               one line rather than two sizes. */
            font-size: 0.9rem;
            font-weight: 600;
            transition: gap 0.2s ease;
            /* 22x20 before, under the 24x24 floor for a tap target — on the one
               link a card offers. The padding grows the hit area without moving
               the text: the negative left margin pulls the box back so the label
               still starts flush with the card's edge. */
            min-height: 24px;
            padding: 2px 8px;
            margin-left: -8px;
}

.blog-card-read:hover {
    gap: 9px;
}

.cat-cafards .blog-card-category-label {
    color: #dc3545;
}

.cat-punaises .blog-card-icon {
    background: rgba(111, 66, 193, 0.1); color: #6f42c1;
}

.cat-punaises .blog-card-category-label {
    color: #6f42c1;
}

.cat-rongeurs .blog-card-icon {
    background: rgba(255, 107, 53, 0.1); color: var(--orange);
}

.cat-rongeurs .blog-card-category-label {
    color: var(--orange);
}

.cat-rats .blog-card-icon {
    background: rgba(230, 126, 34, 0.1); color: #e67e22;
}

.cat-rats .blog-card-category-label {
    color: #e67e22;
}

.cat-souris .blog-card-icon {
    background: rgba(243, 156, 18, 0.1); color: #f39c12;
}

.cat-souris .blog-card-category-label {
    color: #f39c12;
}

.cat-fourmis .blog-card-icon {
    background: rgba(0, 184, 148, 0.1); color: #00b894;
}

.cat-fourmis .blog-card-category-label {
    color: #00b894;
}

.cat-puces .blog-card-icon {
    background: rgba(232, 67, 147, 0.1); color: #e84393;
}

.cat-puces .blog-card-category-label {
    color: #e84393;
}

.cat-mite .blog-card-icon {
    background: rgba(162, 155, 254, 0.1); color: #a29bfe;
}

.cat-mite .blog-card-category-label {
    color: #a29bfe;
}

.cat-taupes .blog-card-icon {
    background: rgba(99, 110, 114, 0.1); color: #636e72;
}

.cat-taupes .blog-card-category-label {
    color: #636e72;
}

.cat-mouches .blog-card-icon {
    background: rgba(9, 132, 227, 0.1); color: #0984e3;
}

.cat-mouches .blog-card-category-label {
    color: #0984e3;
}

.cat-moustique .blog-card-icon {
    background: rgba(0, 206, 209, 0.1); color: #00ced1;
}

.cat-moustique .blog-card-category-label {
    color: #00ced1;
}

.cat-araignee .blog-card-icon {
    background: rgba(45, 52, 54, 0.1); color: #2d3436;
}

.cat-araignee .blog-card-category-label {
    color: #2d3436;
}

.cat-poisson .blog-card-icon {
    background: rgba(116, 185, 255, 0.1); color: #74b9ff;
}

.cat-poisson .blog-card-category-label {
    color: #74b9ff;
}

.cat-termites .blog-card-icon {
    background: rgba(180, 83, 9, 0.1); color: #b45309;
}

.cat-termites .blog-card-category-label {
    color: #b45309;
}

.cat-guepe .blog-card-icon {
    background: rgba(253, 203, 110, 0.15); color: #cc8400;
}

.cat-guepe .blog-card-category-label {
    color: #cc8400;
}

.cat-pigeons .blog-card-icon {
    background: rgba(108, 92, 231, 0.1); color: #6c5ce7;
}

.cat-pigeons .blog-card-category-label {
    color: #6c5ce7;
}

.cat-parasites .blog-card-icon {
    background: rgba(214, 48, 49, 0.1); color: #d63031;
}

.cat-parasites .blog-card-category-label {
    color: #d63031;
}

.btn-load-more {
    display: inline-flex;
            align-items: center;
            gap: 8px;
            background: var(--navy);
            color: var(--white);
            padding: 14px 36px;
            border-radius: 50px;
            font-family: 'Inter', sans-serif;
            font-weight: 600;
            font-size: 0.95rem;
            border: none;
            cursor: pointer;
            transition: all 0.2s ease;
}

.btn-load-more:hover {
    background: var(--navy-light);
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}

.no-results i {
    font-size: 3rem;
            color: var(--gray);
            margin-bottom: 16px;
}

.no-results h3 {
    font-size: 1.2rem;
            color: var(--text-dark);
            margin-bottom: 8px;
}

.no-results p {
    color: var(--gray);
            font-size: 0.95rem;
}


/* The keyframes the hero and cover animations reference. Without them the
   `animation: ... forwards` rules never run and every animated element stays at
   opacity 0 — the article's own title included. */
@keyframes slideUp {
    from { opacity: 0; transform: translateY(40px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* The base rules the whitelist extractor lost — only their media-query variants
   survived, so on desktop the hero had no padding, no tint and no centring, and
   the grid was not a grid at all.

   `.container` is scoped under .blog-redesign rather than declared globally:
   the front already has a .container from the legacy theme, and redefining it
   site-wide from a blog sheet would reach every other page.

   The hero padding is 16px rather than the mockup's 140px for the same reason
   as on the article — 140 is mostly there to clear a position:fixed navbar the
   front does not have. */
.blog-redesign .container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px;
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
}

.blog-hero {
    padding: 16px 20px 50px;
    background: var(--gray-light);
    text-align: center;
    position: relative;
    overflow: hidden;
}

.blog-section {
    padding: 32px 0 80px;
}

.blog-section-title {
    font-size: 1.6rem;
    font-weight: 800;
    margin: 0 0 24px;
}

.blog-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
}

@media (max-width: 992px) {
    .blog-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* The hero is the whole first screen on a phone: measured at 360x740 it ran
   384px tall, and with the section title, the filters and the search below it
   the first article card started at 872px — 132px under the fold, so the page
   opened on a promise of "7 articles disponibles" and not one article.

   Tightened here rather than in the 768/480 blocks at the top of the file:
   those set `.blog-hero` too, but the base rule further down carries the same
   specificity and comes later, so it wins and they never applied. Same reason
   this block redeclares the h1 size — the base `clamp()` would otherwise keep
   2.2rem all the way down. */
@media (max-width: 600px) {
    .blog-hero {
        padding: 12px 16px 24px;
    }

    /* Hidden, NOT removed from the template: the markup still ships both to
       the crawler (Google indexes display:none text, and this page is thin —
       294 words, an h1 that carries no keyword), while the phone gets the
       142px they cost back. Delete them from home.html and the blog index
       loses the only "nuisibles" wording it has outside the article titles.

       The badge goes on EVERY blog hero: it names the section the breadcrumb
       right above it already names, and on a category page the h1 ("Rongeurs")
       has already said more than "Le Blog Anti-Nuisibles" ever does.

       The subtitle is scoped to the INDEX hero, because the category pages
       reuse these classes and there it is the category's own description_front
       — "Des problèmes de punaises de lit ? ..." — the one line that says what
       the page is about. Unscoped, this rule hid it on every phone. */
    .blog-hero-badge {
        display: none;
    }

    .blog-hero-index .blog-hero-subtitle {
        display: none;
    }

    .blog-hero h1 {
        font-size: 1.9rem;
        margin-bottom: 12px;
    }

    .blog-grid {
        grid-template-columns: 1fr;
    }
}

/* --- Search over the article grid ------------------------------------------
   Filters the grid below it, on articles already in the page. */
.blog-search {
    display: flex;
    align-items: center;
    gap: 10px;
    max-width: 520px;
    margin: 0 auto 12px;
    padding: 0 18px;
    background: var(--white);
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 50px;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.blog-search:focus-within {
    border-color: var(--orange);
    box-shadow: 0 0 0 3px rgba(255, 107, 53, 0.15);
}

.blog-search .vd-icon {
    flex: none;
    color: var(--gray);
}

/* Visible to a screen reader, not on screen: the placeholder carries the same
   words for a sighted reader, and a placeholder is not a label. */
.blog-search-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.blog-search-input {
    flex: 1 1 auto;
    min-width: 0;
    /* 44px is the comfortable end of a tap target, and this is the one control
       on the page a reader is meant to aim at. */
    min-height: 44px;
    border: 0;
    outline: 0;
    background: none;
    font: inherit;
    font-size: 0.95rem;
    color: var(--text-dark);
}

.blog-search-input::placeholder {
    color: var(--gray);
}

.blog-search-status,
.blog-search-empty {
    text-align: center;
    color: var(--gray);
    font-size: 0.9rem;
    margin: 0 0 16px;
    min-height: 1.2em;
}

.blog-search-empty {
    padding: 24px 0;
    color: var(--text-body);
}

/* The search runs on a pause in typing, so the button is the affordance for a
   reader who types and waits — and it is what submits the form when there is
   no JavaScript to intercept it. */
.blog-search-submit {
    flex: none;
    /* Own margin rather than the pill's padding: the button sits flush against
       the right edge of the rounded field. */
    margin: 4px -12px 4px 4px;
    padding: 0 20px;
    min-height: 40px;
    border: 0;
    border-radius: 50px;
    background: var(--orange);
    color: var(--white);
    font: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s ease;
}

/* Literal rather than a token: the palette has --orange-light but no darker
   step, and lightening a filled orange button drops white text to 2.4:1.
   This darker step holds 3.5:1, which clears AA for the bold 14px label. */
.blog-search-submit:hover,
.blog-search-submit:focus-visible {
    background: #e85d2a;
}

/* --- Category filters, in place of the card grid ---------------------------
   The mockup turns the categories into chips beside the search rather than a
   grid of covers ahead of the articles: a reader arriving on a blog wants the
   writing, and a full row of category cards pushed all of it below the fold. */
.blog-filters {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    max-width: 900px;
    margin: 0 auto 16px;
}

.blog-filter {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* 36px: a chip is a tap target before it is a label. */
    min-height: 36px;
    padding: 6px 16px;
    border: 1px solid rgba(0, 0, 0, 0.08);
    border-radius: 50px;
    background: var(--white);
    color: var(--text-body);
    font: inherit;
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.blog-filter:hover {
    border-color: var(--orange);
    color: var(--orange);
}

.blog-filter.is-active {
    background: var(--orange);
    border-color: var(--orange);
    color: var(--white);
}

.blog-filter-count {
    opacity: 0.75;
    font-weight: 500;
}

/* The mobile face of the same filter: chips give way to a native select.

   Measured on a 360x740 screen with the production categories: the 16 chips
   wrap to 7 rows, 304px — more than the hero above them (191px) — and push the
   first article card 118px under the fold. The select is one control, ~50px,
   and the system opens it full screen with all 16 visible at once.

   Desktop keeps the chips: at 1200px they cost a row or two and filtering is
   one click, which a select cannot match with a mouse.

   Placed AFTER the .blog-filters rules above, not with the other mobile rules
   further up the file: a media query adds no specificity, so a block sitting
   before them would lose to them and apply nothing at all. */
.blog-filter-select {
    display: none;
    max-width: 520px;
    margin: 0 auto 16px;
    padding: 0 18px;
    text-align: left;
}

.blog-filter-select-label {
    display: block;
    margin-bottom: 6px;
    color: var(--gray);
    font-size: 0.8rem;
    font-weight: 600;
}

.blog-filter-select-input {
    width: 100%;
    /* 44px: the control is a tap target before it is a list. */
    min-height: 44px;
    padding: 10px 14px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    border-radius: 12px;
    background: var(--white);
    color: var(--text-dark);
    font: inherit;
    font-size: 1rem;
    font-weight: 600;
}

@media (max-width: 600px) {
    .blog-filters {
        display: none;
    }

    .blog-filter-select {
        display: block;
    }
}

/* --- Search feedback --------------------------------------------------------
   The grid has to say when it changes. On a phone it starts at 625px of a 740px
   screen — one card visible while the reader types — so narrowing 26 articles
   to 3 could happen entirely off screen, and a reader who sees nothing move
   concludes the search is broken rather than pending.

   Two states: dimmed while the request is in flight, then a short fade replayed
   on the new list. */
.blog-grid {
    transition: opacity 0.15s ease;
}

.blog-grid.is-searching {
    opacity: 0.45;
}

.blog-grid.is-updated {
    animation: blog-grid-refresh 0.35s ease;
}

@keyframes blog-grid-refresh {
    from {
        opacity: 0.45;
        transform: translateY(4px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

/* The count line is the other half of the answer, and it is the half a screen
   reader gets. It carries role="status", so it is announced either way. */
.blog-search-status {
    min-height: 1.2em;
}

/* A reader who asked for less motion still gets the dimming, which is a state
   rather than an animation. */
@media (prefers-reduced-motion: reduce) {
    .blog-grid,
    .blog-grid.is-updated {
        animation: none;
        transition: none;
    }
}
