/* ============================================================================
   LS FABRICATION — INSTALL GUIDE INDEX AND CARDS
   Markup: inc/lsfab-guide-index.php.  Behaviour: js/guide-index.js.

   One card, three homes: the Installation Manuals page, the blog index, and
   every category archive. It replaces Divi's blog module, which was salvattore
   masonry — three columns of cards that started at different heights, never
   lined up, and each carried 154 characters of the post body as an "excerpt",
   which on an install guide is the middle of step one.

   Loaded on blog pages AND on page 144537, which is not a blog page, so this
   sheet may not lean on anything in blog.css. Tokens from style.css only.
   ========================================================================= */

/* ----------------------------------------------------------------------------
   1. GRID
   `auto-fill` with a min track, not a fixed column count: the same grid is
   1200px wide on the manuals page and ~900px beside the archive rail, and it
   should decide for itself that one is four columns and the other is three.
   `min(100%, 250px)` rather than a bare 250px — a bare minimum larger than the
   container is the classic way a grid overflows a 320px phone.
   ------------------------------------------------------------------------- */

.ls-ggrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
    gap: var(--ls-space-5);
    margin: 0;
    padding: 0;
    list-style: none;
}


/* ----------------------------------------------------------------------------
   2. THE CARD
   ------------------------------------------------------------------------- */

.ls-gcard { display: flex; }

/*
   `hidden` is how js/guide-index.js filters, and a class selector beats the
   user agent's `[hidden] { display: none }` — so the rule above silently kept
   every filtered-out card on screen. Restated at higher specificity rather than
   filtering with a class of our own, because `hidden` is also what a screen
   reader and find-in-page honour.
*/
.ls-gcard[hidden] { display: none; }

/*
   The whole card is the anchor. The old cards put a "READ MORE" link under the
   excerpt, so a 370px card had a 90px hit area — a poor target on a phone and a
   worse one in a workshop.
*/
.ls-gcard .ls-gcard__link {
    display: flex;
    flex-direction: column;
    width: 100%;
    background: var(--ls-surface-1);
    border: 1px solid var(--ls-hairline);
    border-radius: var(--ls-radius-xl);
    overflow: hidden;
    text-decoration: none;
    transition: border-color var(--ls-transition), transform var(--ls-transition), box-shadow var(--ls-transition);
}

.ls-gcard .ls-gcard__link:hover {
    border-color: rgba(255, 0, 68, 0.45);
    transform: translateY(-2px);
    box-shadow: var(--ls-shadow-drop);
}

.ls-gcard .ls-gcard__link:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: 3px;
}

/* A fixed ratio is what makes the rows line up. Divi let each image keep its
   own aspect, which is where the ragged columns came from. */
.ls-gcard__media {
    position: relative;
    display: block;
    aspect-ratio: 4 / 3;
    background: var(--ls-surface-2);
    overflow: hidden;
}

.ls-gcard__media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    margin: 0;
    transition: transform 400ms ease;
}

.ls-gcard .ls-gcard__link:hover .ls-gcard__media img { transform: scale(1.04); }

/* One guide in 53 has no featured image. A monogram on the steel gradient beats
   both the empty black box Divi rendered and a stock photo of the wrong part. */
.ls-gcard__mono {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--ls-font-display);
    font-size: 3.5rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    color: var(--ls-text-ghost);
}

/* Solid, not the steel gradient clipped to the text. That gradient runs to
   #2B2E31 at its right end, which on this ground is black — the second letter
   of the monogram disappeared. A placeholder has one job and no reason to be
   clever about it. */

.ls-gcard__flags {
    position: absolute;
    top: 10px;
    left: 10px;
    display: flex;
    gap: 6px;
}

.ls-gcard__flag {
    display: inline-block;
    padding: 5px 8px;
    border-radius: var(--ls-radius-sm);
    background: rgba(0, 0, 0, 0.72);
    font-family: var(--ls-font-body);
    font-size: var(--ls-caption);
    font-weight: 600;
    letter-spacing: var(--ls-tracking-eyebrow);
    text-transform: uppercase;
    line-height: 1;
    color: #ffffff;
}

.ls-gcard__flag.is-video { background: rgba(224, 0, 56, 0.92); }

.ls-gcard__body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 6px;
    padding: var(--ls-space-4) var(--ls-space-4) var(--ls-space-5);
}

.ls-gcard__eyebrow {
    display: block;
    font-family: var(--ls-font-body);
    font-size: var(--ls-micro);
    font-weight: 600;
    letter-spacing: var(--ls-tracking-eyebrow);
    text-transform: uppercase;
    line-height: 1;
    color: var(--ls-cyan);
}

/*
   NO -webkit-line-clamp on the title. It is a flex item, flex items are
   blockified, `display:-webkit-box` computes to `flow-root`, and the clamp
   silently does nothing while overflow:hidden still cuts text mid-glyph — the
   same trap the product cards hit. Titles wrap freely instead; the grid row
   stretches every card to match, and .ls-gcard__part is pushed to the bottom
   with margin-top:auto so the part line sits on one baseline across a row.
*/
.ls-gcard .ls-gcard__title {
    margin: 0;
    font-family: var(--ls-font-display);
    font-size: var(--ls-h4);
    font-weight: 600;
    line-height: var(--ls-leading-h4);
    color: var(--ls-text);
    transition: color var(--ls-transition);
}

.ls-gcard .ls-gcard__link:hover .ls-gcard__title { color: var(--ls-red); }

.ls-gcard__part {
    display: block;
    margin-top: auto;
    padding-top: var(--ls-space-3);
    font-size: var(--ls-small);
    line-height: 1.35;
    color: var(--ls-text-soft);
}

/* The rule reads as a divider between "what this guide is" and "what it
   installs", which is the one distinction the card has to make. */
.ls-gcard__part::before {
    content: "";
    display: block;
    width: 24px;
    height: 2px;
    margin-bottom: var(--ls-space-3);
    background-image: var(--ls-gradient-ui);
    border-radius: var(--ls-radius-pill);
}


/* ----------------------------------------------------------------------------
   3. THE FILTER BAR
   Only on the two pages that show the whole library. On a nine-card archive a
   "filter these 9" control is furniture — the rail beside it is how you change
   truck there.
   ------------------------------------------------------------------------- */

.ls-gfilter {
    display: flex;
    flex-direction: column;
    gap: var(--ls-space-4);
    margin-bottom: var(--ls-space-6);
}

.ls-gfilter__searchwrap { position: relative; }

/* Inline SVG rather than the icon font: this sheet loads on a page where
   icon-font.css does not, and a magnifier that renders as a tofu box is worse
   than no magnifier. */
.ls-gfilter__searchwrap::before {
    content: "";
    position: absolute;
    left: 16px;
    top: 50%;
    width: 18px;
    height: 18px;
    transform: translateY(-50%);
    pointer-events: none;
    background: no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-opacity='.55' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E");
}

.ls-gfilter .ls-gfilter__input {
    width: 100%;
    min-height: var(--ls-control-h);
    padding: 0 var(--ls-space-4) 0 46px;
    background: var(--ls-surface-2);
    border: 1px solid var(--ls-hairline-input);
    border-radius: var(--ls-radius-md);
    font-family: var(--ls-font-body);
    font-size: var(--ls-body);
    color: var(--ls-text);
    -webkit-appearance: none;
    appearance: none;
}

.ls-gfilter .ls-gfilter__input::placeholder { color: var(--ls-text-faint); }

.ls-gfilter .ls-gfilter__input:focus {
    outline: none;
    border-color: var(--ls-red);
    box-shadow: var(--ls-focus-ring);
}

.ls-gfilter__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ls-space-2);
}

/* 44px minimum, the site's tap-target standard. A chip row is exactly the kind
   of control that gets used on a phone in a driveway. */
.ls-gfilter .ls-gfilter__chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 var(--ls-space-4);
    background: var(--ls-surface-2);
    border: 1px solid var(--ls-hairline);
    border-radius: var(--ls-radius-pill);
    font-family: var(--ls-font-body);
    font-size: var(--ls-small);
    font-weight: 600;
    line-height: 1;
    color: var(--ls-text-muted);
    cursor: pointer;
    transition: background-color var(--ls-transition), border-color var(--ls-transition), color var(--ls-transition);
}

.ls-gfilter .ls-gfilter__chip:hover {
    background: var(--ls-surface-raised);
    color: var(--ls-text);
}

.ls-gfilter .ls-gfilter__chip.is-on {
    background: var(--ls-red-btn);
    border-color: transparent;
    color: #ffffff;
}

.ls-gfilter__n {
    font-variant-numeric: tabular-nums;
    font-size: var(--ls-caption);
    color: var(--ls-text-ghost);
}

.ls-gfilter .ls-gfilter__chip.is-on .ls-gfilter__n { color: rgba(255, 255, 255, 0.75); }

/* Empty until the script writes to it, so it takes no vertical space on a page
   where the filter has not been touched. */
.ls-gfilter .ls-gfilter__count {
    margin: 0;
    font-size: var(--ls-small);
    color: var(--ls-text-faint);
    min-height: 0;
}

.ls-gempty {
    margin: var(--ls-space-7) 0;
    padding: var(--ls-space-6);
    background: var(--ls-surface-1);
    border: 1px solid var(--ls-hairline);
    border-radius: var(--ls-radius-xl);
    text-align: center;
    font-size: var(--ls-body);
    color: var(--ls-text-muted);
}


/* ----------------------------------------------------------------------------
   4. NARROW
   ------------------------------------------------------------------------- */

/* ----------------------------------------------------------------------------
   5. THE MANUALS PAGE ROW
   Divi's own mobile stylesheet sets `.et_pb_row { width: 80% }` and beats the
   90% the module asks for, so the index sat in 300px of a 375px screen while
   every archive on the site sits in 338px — 38px of gutter against 18px, on
   pages a reader moves between. The class is set in the row's own Divi settings
   (module_class), never guessed at with a row index, because that index moves
   the next time somebody adds a row in the builder.
   ------------------------------------------------------------------------- */

@media (max-width: 980px) {
    body .et-l .et_pb_row.ls-gindex-row { width: 90%; }
}


@media (max-width: 600px) {

    .ls-ggrid { gap: var(--ls-space-4); }

    /* One column of 4:3 photos scrolls forever on a phone. Side by side, the
       image is small enough that eight guides fit on a screen and the title
       still carries the meaning. */
    .ls-gcard .ls-gcard__link { flex-direction: row; }

    /* Stretched, not square. A fixed 1:1 thumbnail left a seam under itself on
       any card whose title ran to three lines; a full-height strip reads as one
       object and needs no per-card height. */
    .ls-gcard__media {
        flex: 0 0 118px;
        aspect-ratio: auto;
        align-self: stretch;
        min-height: 118px;
    }

    .ls-gcard__body {
        padding: var(--ls-space-3) var(--ls-space-4);
        justify-content: center;
    }

    .ls-gcard .ls-gcard__title { font-size: var(--ls-h4); line-height: var(--ls-leading-h4); }

    .ls-gcard__flags { top: 6px; left: 6px; }
    .ls-gcard__flag { padding: 4px 6px; font-size: var(--ls-caption); }

    /* The part line is the first thing to go when the card is 118px tall — the
       title already names the part on every guide in the library. */
    .ls-gcard__part { display: none; }

    .ls-gcard__mono { font-size: 2rem; }
}
