/*
 * screener-funds.css
 *   /screener-funds
 * Version 1.0.0
 *
 * THE VOCABULARY IS THE FUND PAGES', TOKEN FOR TOKEN.
 * ---------------------------------------------------------------------
 * bq-ownership's funds.css already decided what a Business Quant fund
 * surface looks like, and a screener that lists the funds those pages
 * describe is the same kind of surface: warm-neutral ink rather than
 * blue-grey, hairlines instead of boxes inside boxes, 11px/700/uppercase
 * micro-labels for chrome, tabular figures wherever a number can change
 * under the reader, teal for what a fund OWNS and amber for what it
 * COSTS, and green/red reserved for DIRECTION and never for decoration.
 * A second design system for the page that links to those pages would be
 * a third on a site that should have one.
 *
 * Lato comes from the global stylesheet, which forces it with
 * !important on everything. Weight, size, tracking and figure style do
 * all the work here.
 *
 * ONE TABLE, TWO LAYOUTS.
 * Above 700px this is a table: sticky header, sticky first column, eight
 * to forty columns scrolling horizontally inside their own box and never
 * widening the page. Below it, every <tr> becomes a card and every <td>
 * a stacked label/value pair in a TWO-COLUMN GRID.
 *
 * The grid is why the mobile layout is even. A phone-width screener
 * rendered as label-left/value-right rows puts every value against the
 * right edge with a river of white down the middle, and a row of eight
 * metrics of which three are em dashes looks broken. Two even columns of
 * stacked pairs fill the card whatever the mix, and the LAST CELL SPANS
 * BOTH COLUMNS when the count is odd — see the :last-child:nth-child(even)
 * rule — so a card never ends with a half-empty row.
 */

/* =====================================================================
   LATO -- VENDORED, NOT BORROWED
   =====================================================================
   These faces used to come from bq-global-layout/assets/css/lato.css,
   reached through the mu-router's dependency closure. That worked, but it
   made this page's type depend on another plugin staying in a keep-list
   seventeen routes long -- and the failure is silent: `body` sets
   font-synthesis: none site-wide, so a missing 600 does not fall back to a
   faked semibold, it renders as Bold, and a missing 400 renders as
   whatever the fallback stack has. The files are 440KB and they are now in
   this plugin's own assets/fonts.

   THE FAMILY NAME IS STILL 'Lato', DELIBERATELY. global-styles.css carries
   `* { font-family: var(--bq-lato) !important; }`, so nothing this file
   declares under a private name would ever be painted. Declaring the same
   family means these URLs simply satisfy that rule. Where both stylesheets
   declare the same family/weight/unicode-range the browser resolves to one
   of them and downloads once, so this costs nothing on a page that also
   loads bq-global-layout.

   ONLY THE THREE WEIGHTS THIS PAGE USES. 400 for values and prose, 600 for
   the one real Semibold cut (Google's Lato has none -- this is the foundry
   file, same OFL, copied from bq-global-layout), 700 for tickers, labels
   and column heads. The rest of the family is in ../fonts unused; adding a
   500 or an 800 rule would resolve to 400 and 900 and is what the note in
   bq-pages/assets/css/lato.css warns against.
   ===================================================================== */

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 400;
    font-display: block;
    src: url('../fonts/lato-400-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 400;
    font-display: block;
    src: url('../fonts/lato-400-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 700;
    font-display: block;
    src: url('../fonts/lato-700-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 700;
    font-display: block;
    src: url('../fonts/lato-700-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 600;
    font-display: block;
    src: url('../fonts/Lato-Semibold.woff2') format('woff2'),
         url('../fonts/Lato-Semibold.woff') format('woff');
}


/* =====================================================================
   THE PALETTE
   ===================================================================== */
.bq-sf {
    /* THE HOUSE PALETTE, NOT A WARM ONE.
       The first build took its greys from bq-ownership/funds.css, which is
       genuinely warm -- #16202b ink on an #f4f3f0 ground -- because a fund
       DETAIL page is a long read and a warm ground is easier on one. This
       is not that page. It is a dense table next to /stocks, company-KPI
       and the watchlist, all of which are #0b1f2e on #f5f7f9 with #00529b
       accents, and a warm-grey table beside them does not read as calmer;
       it reads as unwashed. These values are those files' exactly:
       --ck-* in company-KPI/css/styles.css and --io-* in
       bq-ownership/assets/css/overview.css, which are already copies of
       each other. Keep the three in step. */
    --sf-ink:        #0b1f2e;
    --sf-text:       #37485a;
    --sf-muted:      #6b7a89;
    --sf-faint:      #97a4b2;

    /* These are the :root set in bq-pages/assets/css/homepage.css, which
       is what /top-gainers and the stock lists paint with -- the crispest
       tables on the site and the ones this sits beside. They are within a
       hair of company-KPI's --ck-* (#eaeff4/#cfd9e3); where the two
       disagree by a shade, the movers pages win, because that is the page
       a reader arrives here from. */
    --sf-line:       #e7edf2;
    --sf-line-mid:   #dfe6ed;
    --sf-line-strong:#cdd7e0;

    --sf-page:       #f5f7f9;
    --sf-card:       #ffffff;
    --sf-tint:       #f5f8fa;   /* --bq-panel-head */
    --sf-tint-2:     #f1f6fa;
    --sf-hover:      #f4f8fb;   /* --bq-row-hover */
    --sf-navy:       #002a45;   /* --blue-darkest, the header underline */

    /* Neutral greys with no blue in them, for the surfaces that REPEAT
       down a long column -- the table head, the rail head, the chooser's
       rows. company-KPI's note on --ck-grey is the reason: enough of a
       blue-leaning tint in one place stops reading as white and starts
       reading as a coloured panel. */
    --sf-grey:       #f8f9fa;
    --sf-grey-2:     #f1f3f5;

    /* Hues that MEAN something. Blue is the site's accent and its link
       colour; amber is what a fund costs and is the gate; green and red
       are direction and nothing else may borrow them. The four vehicle
       badges are the one place a wider set is needed, and they get one
       hue each so the badge is legible without reading the word. */
    --sf-accent:       #00529b;
    --sf-accent-deep:  #003d75;
    --sf-accent-soft:  rgba(0, 82, 155, .08);

    /* --ck-blue-mid in company-KPI. The pager's current page was --sf-ink,
       a near-black navy that read as a heavy black square at the bottom of
       a light page. This is the shade the KPI controls use for their own
       active state, and .bq-pagination-controls .page-btn.active on
       /sec-filings is within a hair of it (#0073aa). */
    --sf-accent-mid:   #217ab4;

    /* WHAT AN ACTIVE FILTER LOOKS LIKE, AND IT IS NOT BLUE.
       Blue on this page is navigation -- links, the focus ring, the page
       you are on. A filter you have applied is a different kind of state
       and was wearing the same colour, so a lit rail badge and the current
       page number were indistinguishable at a glance. Teal is already in
       the palette and carries no other job here.

       GOLD WAS TRIED HERE AND REJECTED, so this is not an idea to have
       again. Warm-against-cool did separate state from navigation more
       sharply than teal does, but a gold fill on the view bar and a gold
       rule under the table head put the two loudest objects on the page in
       a colour fighting the navy site header directly above them. Teal
       stays. --sf-active-line is the one thing kept from that pass: the
       chip border was a hard-coded rgba() of this same hue in two separate
       places, which is a token by any other name. */
    --sf-active:       #0e8577;
    --sf-active-deep:  #0a6b5f;
    --sf-active-soft:  rgba(14, 133, 119, .10);
    --sf-active-line:  rgba(14, 133, 119, .22);
    --sf-amber:      #b0761a;
    --sf-amber-soft: rgba(176, 118, 26, .12);
    --sf-teal:       #0e8577;
    --sf-violet:     #6455d8;

    --sf-green:      #15803d;
    --sf-red:        #c5331f;

    /* SQUARE, AND ON PURPOSE. Every other bordered surface on the site --
       .bq-sl-head on the stock lists, .bq-example in the content pages --
       is a 1px rule with no radius at all, and a 10px corner beside them
       read as a different product. A control keeps 2px so the border does
       not come to a literal point; a PANE keeps none.

       The shadows went with them. A hairline in --sf-line-strong is what
       separates a pane from the page here; a soft drop shadow under every
       card is the other house style, not this one. --sf-shadow-lg stays
       for the two things that genuinely float above the page: the column
       modal and the mobile filter sheet. */
    --sf-radius:     0;
    --sf-radius-sm:  3px;   /* --radius in bq-pages, exactly */

    /* THE TABLE BOX IS A FIXED NUMBER OF ROWS TALL.
       Not min-height, not max-height: a constant. A box that shrinks to two
       rows when a filter bites and grows back on the next keystroke makes
       the whole page jump under the reader, and the pager and the footnote
       move with it. --sf-rows is written on the element by PHP and by the
       script from the SAME page size (BQ_SF_PAGE_SIZE), so the box is
       exactly as tall as a full page of results whatever is in it.

       This works only because every row is now exactly one line: the fund
       name left the cell, and nothing else in a row can wrap. */
    --sf-row-h:      31px;
    --sf-head-h:     33px;
    --sf-rows:       50;
    --sf-shadow:     none;
    --sf-shadow-lg:  0 10px 40px rgba(22, 32, 43, .16);

    /* The fixed global header is 54px. Every offset on this page derives
       from this rather than repeating the number. */
    --sf-header-h:   54px;

    color: var(--sf-text);
    font-size: 14px;
    line-height: 1.5;
}

body { padding-top: 54px; background: var(--sf-page, #f5f7f9); }

.bq-sf *, .bq-sf *::before, .bq-sf *::after { box-sizing: border-box; }

/* `hidden` MUST WIN, and without this it does not.
   The browser's own `[hidden] { display: none }` is a user-agent rule with
   effectively zero specificity, so ANY class rule here that sets a display
   value beats it — and half a dozen of them do. The result is a loading
   spinner and an empty state that are permanently on screen while
   `el.hidden` reads true in the console, which is a genuinely confusing
   thing to debug. Anything toggled with `hidden` in the JS relies on this
   line. */
.bq-sf [hidden] { display: none !important; }

.bq-sf-page {
    max-width: 1680px;
    margin: 0 auto;
    padding: 20px 20px 64px;
}

/* Tabular figures everywhere a number sits in a column. Proportional
   digits make a column of returns jitter as the rows change under a
   filter, which reads as the table redrawing wrongly. */
.bq-sf .bq-sf-td.is-num,
.bq-sf .bq-sf-th.is-num,
.bq-sf .bq-sf-stamp-v,
.bq-sf .bq-sf-count strong,
.bq-sf .bq-sf-range input,
.bq-sf .bq-sf-pager button {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}


/* =====================================================================
   PAGE HEAD
   ===================================================================== */
.bq-sf-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
    padding: 4px 2px 18px;
}

.bq-sf-eyebrow {
    margin: 0 0 6px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--sf-accent);
}

.bq-sf-title {
    margin: 0 0 8px;
    font-size: 30px;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -.02em;
    color: var(--sf-ink);
}

.bq-sf-lede {
    margin: 0;
    max-width: 68ch;
    font-size: 14.5px;
    color: var(--sf-muted);
    line-height: 1.55;
}
/* NO BOLD IN THE LEDE. Three bolded fragments in one sentence is not
   emphasis -- nothing is emphasised when everything is, and the eye stops at
   each one instead of reading the line. The <strong> tags stay in the markup,
   where the number genuinely is the point for anything reading the document
   structure; they simply do not take a heavier face here. */
.bq-sf-lede strong { color: inherit; font-weight: 400; }

/* THE STAMPS DISAGREE ON PURPOSE. A portfolio is quarterly, a price is
   daily and a prospectus can be a year old, so they are shown as four
   separate readings rather than reconciled into one page-level "as of"
   that would be wrong for three of them. */
.bq-sf-stamps {
    display: flex;
    gap: 0;
    flex-wrap: wrap;
    background: var(--sf-card);
    border: 1px solid var(--sf-line-strong);
    border-radius: var(--sf-radius);
    overflow: hidden;
    box-shadow: var(--sf-shadow);
}

.bq-sf-stamp {
    padding: 9px 16px;
    border-left: 1px solid var(--sf-line);
    min-width: 104px;
}
.bq-sf-stamp:first-child { border-left: 0; }

.bq-sf-stamp-k {
    display: block;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--sf-faint);
    margin-bottom: 3px;
}
.bq-sf-stamp-v {
    display: block;
    font-size: 13px;
    font-weight: 700;
    color: var(--sf-ink);
    white-space: nowrap;
}


/* =====================================================================
   SHELL
   ===================================================================== */
.bq-sf-shell {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}

.bq-sf-main { min-width: 0; }


/* =====================================================================
   FILTER RAIL
   ===================================================================== */
/* NO SCROLLBAR OF ITS OWN. It was a viewport-tall pane with its own
   overflow, which is two nested scroll tracks and neither obviously the
   one to grab. The rail is now exactly as tall as its content and scrolls
   with the page like everything else.

   THE ACCORDION IS WHAT MAKES THIS WORK. Sixteen groups expanded is a
   4,000px rail; one group open at a time is fifteen 44px headers plus one
   body, which is a normal amount of page. The two changes are a pair --
   reverting the accordion without restoring a max-height here gives back a
   rail longer than the results it filters. */
.bq-sf-rail {
    position: sticky;
    top: var(--sf-header-h);
    height: auto;
    max-height: none;
    display: flex;
    flex-direction: column;
    background: var(--sf-card);
    border: 1px solid var(--sf-line-strong);
    border-radius: var(--sf-radius);
    box-shadow: var(--sf-shadow);
}

.bq-sf-rail-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 13px 16px;
    border-bottom: 1px solid var(--sf-line-mid);
    background: var(--sf-tint);
}

.bq-sf-rail-title {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--sf-muted);
    margin-right: auto;
}

.bq-sf-rail-reset {
    appearance: none;
    border: 0;
    background: none;
    padding: 0;
    font: inherit;
    font-size: 12px;
    font-weight: 700;
    color: var(--sf-active);
    cursor: pointer;
}
.bq-sf-rail-reset:hover { color: var(--sf-active-deep); text-decoration: underline; }

.bq-sf-rail-close { display: none; }

.bq-sf-rail-body {
    overflow: visible;
    padding: 4px 0 8px;
    flex: 1 1 auto;
}

.bq-sf-rail-foot { display: none; }

/* Skeleton, so the rail has its height before the script builds it and
   the results column does not jump when it appears. */
.bq-sf-rail-loading { padding: 16px; display: flex; flex-direction: column; gap: 10px; }
.bq-sf-sk {
    display: block;
    height: 12px;
    border-radius: 4px;
    background: linear-gradient(90deg, #f1f3f5 25%, #e3e8ee 50%, #f1f3f5 75%);
    background-size: 400% 100%;
    animation: bq-sf-shimmer 3.2s ease-in-out infinite;
}
.bq-sf-sk:nth-child(even) { height: 30px; }
@keyframes bq-sf-shimmer { 0% { background-position: -400% 0; } 100% { background-position: 400% 0; } }

/* --- a statement group --- */
.bq-sf-group { border-bottom: 1px solid var(--sf-line); }
.bq-sf-group:last-child { border-bottom: 0; }

.bq-sf-group-head {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 11px 16px;
    background: none;
    border: 0;
    font: inherit;
    text-align: left;
    cursor: pointer;
    color: var(--sf-ink);
}
.bq-sf-group-head:hover { background: var(--sf-tint); }

.bq-sf-group-name {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    margin-right: auto;
}

.bq-sf-group-badge {
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--sf-radius-sm);
    background: var(--sf-active);
    color: #fff;
    font-size: 10.5px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
}

.bq-sf-group-caret {
    width: 10px;
    height: 10px;
    fill: var(--sf-faint);
    transition: transform .18s ease;
    flex: none;
}
.bq-sf-group.is-open .bq-sf-group-caret { transform: rotate(180deg); }

.bq-sf-group-body { display: none; padding: 2px 16px 14px; }
.bq-sf-group.is-open .bq-sf-group-body { display: block; }

/* --- one filter --- */
.bq-sf-f { padding: 9px 0; }
.bq-sf-f + .bq-sf-f { border-top: 1px solid var(--sf-line); }

.bq-sf-f-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--sf-ink);
    margin-bottom: 7px;
}

/* The tooltip is the metrics list's `description`, verbatim. It is the
   only place a reader is told that a null expense ratio is not a free
   fund, or that 60% unclassified sector weight is normal. */
.bq-sf-info {
    flex: none;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1px solid var(--sf-line-strong);
    color: var(--sf-faint);
    font-size: 9.5px;
    font-weight: 700;
    line-height: 12px;
    text-align: center;
    cursor: help;
    background: none;
    padding: 0;
}
.bq-sf-info:hover { border-color: var(--sf-accent); color: var(--sf-accent); }

.bq-sf-f-hint {
    display: block;
    margin-top: 6px;
    font-size: 10.5px;
    color: var(--sf-faint);
    letter-spacing: .01em;
}

/* range: two bounds, never a slider drawn to max. Net Expense Ratio maxes
   at 12.44% against a median of 0.83, so a track scaled to the maximum
   would put every usable value in the first 7% of its travel. The
   placeholders are p05 and p95. */
/* NO SPINNERS. The up/down arrows a number input draws are 17px of chrome
   at the right edge of every one of these boxes, they are useless for a
   value like 0.03, and they were what the percent suffix was being pushed
   out past -- which is how the suffix ended up sitting to the RIGHT of the
   arrows instead of beside the figure. */
.bq-sf-range input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.bq-sf-range input[type="number"]::-webkit-outer-spin-button,
.bq-sf-range input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* THE UNIT RIDES ON THE INPUT.
   Two different confusions, two different controls.

   A PERCENT box: is 0.5 half a percent or fifty? The suffix is drawn
   inside the field, in grey, and only once there is something to qualify
   -- `:not(:placeholder-shown)` is what makes an empty box stay clean, and
   it works because every one of these fields carries a placeholder.

   A DOLLAR box: nobody types 5000000000. The pair gets a Mn/Bn select and
   the JS multiplies, so the filter sent to the API is still the raw number
   and only the typing changes. */
.bq-sf-range { display: flex; align-items: center; gap: 7px; }
.bq-sf-inp { position: relative; flex: 1 1 auto; min-width: 0; display: block; }
/* BESIDE THE FIGURE, NOT AT THE EDGE OF THE BOX. `left` is written by the
   script, which measures the typed text in the input's own font -- so the
   suffix reads as part of the number ("0.05%") rather than as a label
   parked in the corner. Hidden by CSS while the box is empty, so an
   untouched filter stays clean.

   NO LAYOUT SHIFT. The right padding is CONSTANT. It used to be applied
   only once something had been typed, which moved the text the instant the
   first character landed -- the shift being reported here. The box now
   reserves the room whether or not it is used. */
.bq-sf-inp > i {
    position: absolute;
    top: 50%;
    left: 0;
    transform: translateY(-50%);
    font-style: normal;
    font-size: 12px;
    font-weight: 400;
    color: var(--sf-faint);
    pointer-events: none;
    white-space: nowrap;
    display: none;
}
.bq-sf-inp > input:not(:placeholder-shown) ~ i { display: block; }
.bq-sf-range input { padding-right: 22px; }

.bq-sf-unit {
    flex: none;
    appearance: none;
    padding: 7px 20px 7px 8px;
    font: inherit;
    font-size: 11.5px;
    font-weight: 700;
    color: var(--sf-muted);
    background: var(--sf-tint-2) url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='%2397a4b2' d='M6 8.5 1.5 4h9z'/%3E%3C/svg%3E") no-repeat right 6px center/9px;
    border: 1px solid var(--sf-line-mid);
    border-radius: var(--sf-radius-sm);
    cursor: pointer;
}
.bq-sf-unit:focus { outline: none; border-color: var(--sf-accent); }

.bq-sf-range input {
    width: 100%;
    min-width: 0;
    padding: 7px 9px;
    font: inherit;
    font-size: 13px;
    color: var(--sf-ink);
    background: var(--sf-tint);
    border: 1px solid var(--sf-line-mid);
    border-radius: var(--sf-radius-sm);
    transition: border-color .15s ease, background .15s ease;
}
.bq-sf-range input:focus {
    outline: none;
    background: #fff;
    border-color: var(--sf-accent);
    box-shadow: 0 0 0 3px var(--sf-accent-soft);
}
.bq-sf-range-dash { color: var(--sf-faint); font-size: 12px; flex: none; }

/* text search inside the rail */
.bq-sf-f input[type="text"] {
    width: 100%;
    padding: 7px 9px;
    font: inherit;
    font-size: 13px;
    background: var(--sf-tint);
    border: 1px solid var(--sf-line-mid);
    border-radius: var(--sf-radius-sm);
    color: var(--sf-ink);
}
.bq-sf-f input[type="text"]:focus {
    outline: none;
    background: #fff;
    border-color: var(--sf-accent);
    box-shadow: 0 0 0 3px var(--sf-accent-soft);
}

/* enum / list: checkboxes, most common first. A long vocabulary scrolls
   inside its own box rather than pushing the rest of the rail down —
   Top Country has 58 values. */
/* The cap is on the SCROLLING variant only. Capping every list put an
   inner scrollbar on Category — eight values, 224px of them against a
   216px ceiling — for the sake of hiding eight pixels. */
.bq-sf-opts { display: flex; flex-direction: column; gap: 1px; margin: 0 -6px; padding: 0 6px; }
.bq-sf-opts.is-scroll {
    max-height: 232px;
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--sf-line);
    border-radius: var(--sf-radius-sm);
    padding: 4px 6px;
    margin: 0;
}

.bq-sf-opt {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 6px;
    border-radius: var(--sf-radius-sm);
    font-size: 13px;
    color: var(--sf-text);
    cursor: pointer;
    user-select: none;
}
.bq-sf-opt:hover { background: var(--sf-tint-2); }
.bq-sf-opt input { flex: none; accent-color: var(--sf-active); width: 14px; height: 14px; margin: 0; cursor: pointer; }
.bq-sf-opt span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bq-sf-opt.is-on { color: var(--sf-ink); font-weight: 600; }

.bq-sf-optfilter {
    width: 100%;
    margin-bottom: 6px;
    padding: 6px 9px;
    font: inherit;
    font-size: 12.5px;
    border: 1px solid var(--sf-line-mid);
    border-radius: var(--sf-radius-sm);
    background: var(--sf-tint);
}
.bq-sf-optfilter:focus { outline: none; border-color: var(--sf-accent); background: #fff; }

/* preset chips on the marquee filters */
.bq-sf-presets { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.bq-sf-preset {
    appearance: none;
    border: 1px solid var(--sf-line-mid);
    background: var(--sf-card);
    border-radius: var(--sf-radius-sm);
    padding: 3px 9px;
    font: inherit;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--sf-muted);
    cursor: pointer;
    transition: all .14s ease;
}
.bq-sf-preset:hover { border-color: var(--sf-active); color: var(--sf-active); background: var(--sf-active-soft); }
.bq-sf-preset.is-on { border-color: var(--sf-active); background: var(--sf-active); color: #fff; }


/* =====================================================================
   TOOLBAR
   ===================================================================== */
.bq-sf-toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
}

.bq-sf-search {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
}
.bq-sf-search svg {
    position: absolute;
    left: 12px;
    width: 16px;
    height: 16px;
    fill: var(--sf-faint);
    pointer-events: none;
}
.bq-sf-search input {
    width: 100%;
    padding: 11px 36px 11px 36px;
    font: inherit;
    font-size: 14px;
    color: var(--sf-ink);
    background: var(--sf-card);
    border: 1px solid var(--sf-line-strong);
    border-radius: var(--sf-radius);
    box-shadow: var(--sf-shadow);
    transition: border-color .15s ease, box-shadow .15s ease;
}
.bq-sf-search input::placeholder { color: var(--sf-faint); }
.bq-sf-search input:focus {
    outline: none;
    border-color: var(--sf-accent);
    box-shadow: 0 0 0 3px var(--sf-accent-soft);
}
.bq-sf-search input::-webkit-search-cancel-button { display: none; }

.bq-sf-search-clear {
    position: absolute;
    right: 8px;
    width: 22px;
    height: 22px;
    border: 0;
    border-radius: var(--sf-radius-sm);
    background: var(--sf-tint-2);
    color: var(--sf-muted);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
}
.bq-sf-search-clear:hover { background: var(--sf-line-mid); color: var(--sf-ink); }

.bq-sf-toolbar-right { display: flex; gap: 8px; flex: none; }

.bq-sf-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 10px 14px;
    /* The comparison page renders "Screen all funds" as an <a>, and the theme
       underlines every link in content. A control that looks like a button
       must not also be underlined like prose. */
    text-decoration: none;
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .01em;
    border-radius: var(--sf-radius);
    border: 1px solid var(--sf-line-strong);
    background: var(--sf-card);
    color: var(--sf-ink);
    cursor: pointer;
    white-space: nowrap;
    box-shadow: var(--sf-shadow);
    transition: border-color .15s ease, color .15s ease, background .15s ease, transform .1s ease;
}
.bq-sf-btn svg { width: 15px; height: 15px; fill: currentColor; flex: none; }
.bq-sf-btn:hover { border-color: var(--sf-accent); color: var(--sf-accent); }
.bq-sf-btn:active { transform: translateY(1px); }

.bq-sf-btn-primary {
    background: var(--sf-accent);
    border-color: var(--sf-accent);
    color: #fff;
}
.bq-sf-btn-primary:hover { background: var(--sf-accent-deep); border-color: var(--sf-accent-deep); color: #fff; }

/* THE LOCK IS AMBER, NOT GREY. Amber is what a fund costs everywhere else
   on the site, and a subscription is a cost; a greyed-out button reads as
   broken rather than as gated. */
/* .is-locked NO LONGER PAINTS ANYTHING. The button used to be amber with
   a padlock for anyone without a subscription, which announced the wall to
   every visitor before they had asked for anything -- a page that looks
   half-disabled on arrival. It is an ordinary Download button now; the
   prompt is raised on the CLICK, by the same code that always raised it,
   and bq_sf_ajax_download() still refuses server-side before a single row
   is fetched. The class stays on the element because the script reads it,
   and so that restoring the old treatment is one rule. */

.bq-sf-btn[disabled] { opacity: .55; pointer-events: none; }


/* =====================================================================
   COLUMN PRESETS
   ===================================================================== */
/* The named views. A reader assessing funds on cost wants six cost columns,
   not to open a 102-row chooser and tick them; that is what every screener
   worth using puts above its table.

   ONE ROW THAT SCROLLS, NOT A WRAPPING BLOCK. Fourteen of these wrap to
   three lines at rail-width and the table starts a third of the way down
   the screen -- which is the same vertical budget the row compaction was
   fought for. The bar is scrolled with a hidden scrollbar and a fade on
   whichever edge still has content, so there is always a visible cue that
   there is more. */
.bq-sf-views {
    display: flex;
    gap: 0;
    margin-bottom: 12px;
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    border: 1px solid var(--sf-line-strong);
    background: var(--sf-card);
    position: relative;
}
.bq-sf-views::-webkit-scrollbar { display: none; }

.bq-sf-view {
    flex: none;
    appearance: none;
    border: 0;
    border-right: 1px solid var(--sf-line);
    background: none;
    padding: 9px 15px;
    font: inherit;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--sf-muted);
    white-space: nowrap;
    cursor: pointer;
    transition: background .13s ease, color .13s ease;
}
.bq-sf-view:last-child { border-right: 0; }
.bq-sf-view:hover { background: var(--sf-tint); color: var(--sf-ink); }

/* The current view is INK, not teal. Teal on this page means what a fund
   owns and is the accent on the filter chips; a second teal object in the
   same 40px of screen made the view bar look like an active filter. */
.bq-sf-view.is-on {
    background: var(--sf-ink);
    color: #fff;
    border-right-color: var(--sf-ink);
}
.bq-sf-view.is-on:hover { background: var(--sf-ink); color: #fff; }

/* The edge fades. Painted on the WRAPPER, not the scroller, because a
   gradient inside an overflow box scrolls away with its content. */
.bq-sf-viewswrap { position: relative; }
.bq-sf-viewswrap::before,
.bq-sf-viewswrap::after {
    content: "";
    position: absolute;
    top: 1px;
    bottom: 13px;
    width: 34px;
    pointer-events: none;
    opacity: 0;
    transition: opacity .15s ease;
    z-index: 1;
}
.bq-sf-viewswrap::before {
    left: 1px;
    background: linear-gradient(90deg, var(--sf-card), rgba(255, 255, 255, 0));
}
.bq-sf-viewswrap::after {
    right: 1px;
    background: linear-gradient(270deg, var(--sf-card), rgba(255, 255, 255, 0));
}
.bq-sf-viewswrap.can-left::before  { opacity: 1; }
.bq-sf-viewswrap.can-right::after { opacity: 1; }


/* =====================================================================
   RESULT BAR
   ===================================================================== */
.bq-sf-resultbar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 10px;
    min-height: 26px;
}

.bq-sf-count { margin: 0; font-size: 13.5px; color: var(--sf-muted); }
.bq-sf-count strong { font-size: 16px; font-weight: 700; color: var(--sf-ink); }
.bq-sf-count-sub { color: var(--sf-faint); }

.bq-sf-filter-toggle { display: none; }

/* active filter chips */
.bq-sf-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 11px; }
.bq-sf-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px 4px 10px;
    border-radius: var(--sf-radius-sm);
    background: var(--sf-active-soft);
    border: 1px solid var(--sf-active-line);
    color: var(--sf-active-deep);
    font-size: 12px;
    font-weight: 600;
}
.bq-sf-chip b { font-weight: 700; }
.bq-sf-chip button {
    width: 16px; height: 16px;
    border: 0; border-radius: var(--sf-radius-sm);
    background: rgba(14, 133, 119, .16);
    color: var(--sf-active-deep);
    font-size: 12px; line-height: 1;
    cursor: pointer; padding: 0;
}
.bq-sf-chip button:hover { background: var(--sf-active); color: #fff; }

.bq-sf-nullnote {
    margin: 0 0 11px;
    padding: 8px 12px;
    border-left: 3px solid var(--sf-amber);
    background: rgba(176, 118, 26, .07);
    border-radius: 0 var(--sf-radius-sm) var(--sf-radius-sm) 0;
    font-size: 12.5px;
    color: #7a5311;
}
.bq-sf-nullnote strong { font-weight: 700; }


/* =====================================================================
   TABLE
   ===================================================================== */
/* THE BOX SCROLLS SIDEWAYS ONLY WHEN IT HAS TO, AND MOST OF THE TIME IT
   DOES NOT.

   The constraint is real: a sticky <thead> pinned to the VIEWPORT and a
   horizontally scrolling container are mutually exclusive in CSS.
   `overflow-x: auto` forces `overflow-y` off `visible`, the wrap becomes
   the sticky positioning context, and `top: 54px` then measures from the
   WRAP rather than the window — the 54px dead band with the first row
   hidden behind it that the first build shipped.

   Two builds drew the wrong conclusion from that and made the box scroll
   unconditionally, which traded the sticky header away on every view
   including the eight-column default, where there was nothing to scroll
   and therefore nothing being bought. The trade only has to be made when
   the columns genuinely overflow. So the wrap has NO overflow of its own,
   and the script adds .has-xscroll when it measures the table wider than
   the box (see syncXScroll() in screener-funds.js):

     · without it — the default eight columns, and anything else that fits
       — nothing scrolls, the viewport is the scrollport, and the header
       pins under the site header where a reader expects it.
     · with it — a thirty-column view — the box owns the X axis, the
       ticker column freezes at its left edge, and the header pins to the
       top of the box instead. Knowing which row you are on beats knowing
       which column while you are scrolling sideways.

   body.bq-sf-route carries the other half: global-styles.css sets
   `overflow-x: hidden` on <body>, which makes the BODY a scroll container
   and defeats a viewport-sticky header before the wrap gets a say. `clip`
   clips identically and creates no scrollport. Below 860px all of this is
   undone entirely — see the cards. */
body.bq-sf-route {
    overflow-x: clip;
    overflow-y: visible;
}
.bq-sf-tablewrap {
    position: relative;
    background: var(--sf-card);
    border: 1px solid var(--sf-line-strong);
    border-radius: var(--sf-radius);
    box-shadow: var(--sf-shadow);

    /* NOTHING, until the script says otherwise. A wrap with no overflow is
       not a scrollport, which is what lets the header below pin to the
       window. There is never a vertical scrollbar either way: the box is
       sized to the full page of rows, so the content cannot be taller. */
    overflow: visible;

    /* MIN-height, not height, and the difference matters. overflow-y is
       hidden, so a hard height would CLIP the last row the moment the real
       row box came out a pixel taller than --sf-row-h -- a font swap, a
       zoom level, a browser rounding a border differently. A minimum gives
       the constant box for a short result set and still lets a full page
       take whatever it actually needs. */
    min-height: calc(var(--sf-head-h) + var(--sf-rows) * var(--sf-row-h));
    overscroll-behavior-x: contain;
}

/* THE WIDE CASE. Set by the script only when the table really is wider
   than the box; see syncXScroll(). Everything the old unconditional rule
   did lives here, and now costs the sticky header only on the views that
   are actually paying for something with it. */
.bq-sf-tablewrap.has-xscroll {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
}
.bq-sf-tablewrap.has-xscroll .bq-sf-table thead th { top: 0; }

.bq-sf-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 13.5px;
}

/* WHITE, UNDER A 2px NAVY RULE -- the signature of .bq-tm-table on the
   movers pages and .bq-sl-table on the stock lists. A grey-filled header
   band is the softer convention and it is not this site's: the weight is
   carried by one dark rule, and the header itself stays the same white as
   the rows so the table reads as one surface rather than two. */
.bq-sf-table thead th {
    position: sticky;
    /* Under the site header, because the WINDOW is the scrollport here.
       Inside a .has-xscroll wrap the scrollport is the box, whose own top
       is already below the site header -- see the override under it. */
    top: var(--sf-header-h);
    z-index: 3;
    background: var(--sf-card);
    border-bottom: 2px solid var(--sf-navy);
    padding: 0;
    text-align: left;
    white-space: nowrap;
}

.bq-sf-table thead .bq-sf-th-id {
    left: 0;
    z-index: 4;
    height: var(--sf-head-h);
    padding: 0 12px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--sf-muted);
}

.bq-sf-sortbtn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    width: 100%;
    height: var(--sf-head-h);
    padding: 0 12px;
    border: 0;
    background: none;
    font: inherit;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--sf-muted);
    cursor: pointer;
    text-align: left;
}
.bq-sf-th.is-num .bq-sf-sortbtn { justify-content: flex-end; text-align: right; }
.bq-sf-sortbtn:hover { color: var(--sf-accent); }

.bq-sf-sort-ic { width: 9px; height: 9px; fill: var(--sf-line-strong); flex: none; }
.bq-sf-th.is-sorted .bq-sf-sortbtn { color: var(--sf-ink); }
.bq-sf-th.is-sorted .bq-sf-sort-ic { fill: var(--sf-accent); }
.bq-sf-th.is-sorted[data-dir="asc"]  .bq-sf-sort-ic { clip-path: inset(0 0 50% 0); }
.bq-sf-th.is-sorted[data-dir="desc"] .bq-sf-sort-ic { clip-path: inset(50% 0 0 0); }

.bq-sf-table tbody tr { transition: background .12s ease; }
.bq-sf-table tbody tr:hover { background: var(--sf-hover); }
.bq-sf-table tbody tr:hover .bq-sf-td-id { background: var(--sf-hover); }
.bq-sf-table tbody tr.is-tipped { background: var(--sf-hover); }
.bq-sf-table tbody tr.is-tipped .bq-sf-td-id { background: var(--sf-hover); }

/* 6px/12px, matching .bq-sl-table on the stock lists and .bq-tm-table on
   the movers pages. With the identity cell down to one line this is what
   sets the row height, and fifty rows at the old 9px-plus-three-lines was
   a table you scrolled past rather than read. */
.bq-sf-table td {
    height: var(--sf-row-h);
    padding: 0 12px;
    border-bottom: 1px solid var(--sf-line);
    color: var(--sf-text);
    white-space: nowrap;
    vertical-align: middle;
}
.bq-sf-table tbody tr:last-child td { border-bottom: 0; }

/* REGULAR, NOT SEMIBOLD. These were 600 -- a real Lato Semibold cut, not a
   synthesised one -- but 600 in near-black across every numeric column
   means the whole grid is emphasised, which is the same as none of it
   being. Weight is left to carry one thing: the ticker. The figures get
   the ink colour and tabular digits, and that is enough to separate them
   from the muted text columns beside them. Matches .bq-sl-table td and
   .bq-tm-table td, which declare no weight at all. */
.bq-sf-td.is-num { text-align: right; font-weight: 400; color: var(--sf-ink); }

/* A text column takes the width of its content and no more. Auto table
   layout hands the leftover width to whichever columns can absorb it,
   which on the default view is Category -- eight short words given 200px
   because nothing else wanted it. Capped, the slack spreads across the
   numeric columns instead, where the figures are. */
.bq-sf-table .bq-sf-td:not(.is-num) { max-width: 150px; overflow: hidden; text-overflow: ellipsis; }
.bq-sf-td.is-null { color: var(--sf-faint); font-weight: 400; }
.bq-sf-td.is-up   { color: var(--sf-green); }
.bq-sf-td.is-down { color: var(--sf-red); }

/* The row's handle, pinned. A screener scrolled sideways to column
   twenty is unreadable without the ticker in view. */
/* ONE LINE, AND THE REST IN THE CARD.
   This cell was ticker + badge, then the fund name on a second line
   clamped to two, then the share class on a third: a 57px row before any
   value in it needed the height, and fifty of those is 2,850px of table
   for fifty funds.

   Now it is one line -- ticker, badge, name, ellipsed -- and the full
   name, the share class and the vehicle are in the hover card, which is
   the same object the KPI tables use. The row is 31px. Nothing was
   dropped; the third line just stopped being printed fifty times over
   for the two rows a reader is actually looking at. */
.bq-sf-td-id {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--sf-card);
    border-right: 1px solid var(--sf-line-mid);
    /* Wide enough that the pill is not crowding the ticker AND that the
       column beside it starts somewhere deliberate. At 108px the ticker,
       the pill and the Category value read as one run of text. */
    min-width: 168px;
    width: 168px;
    padding-right: 20px;
    white-space: nowrap;
    cursor: default;
}

/* THE FUND NAME IS NOT PRINTED IN THE TABLE.
   It was the widest column on the page by a distance -- 300px of the
   viewport, every row, for a string that is the same six words with a
   different suffix down most of a family. The ticker is the handle, the
   name is on the row's hover card with the share class and the full
   vehicle, and the 300px went to the columns a screener is actually read
   for. The span stays in the DOM for the card layout below 700px, where
   there is width for it and no hover to reach a card with. */
.bq-sf-table .bq-sf-name { display: none; }
.bq-sf-idline {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
}

.bq-sf-tk {
    flex: none;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--sf-ink);
    text-decoration: none;
    letter-spacing: -.01em;
}
.bq-sf-tk:hover { color: var(--sf-accent); text-decoration: underline; }

.bq-sf-veh {
    flex: none;
    display: inline-block;
    padding: 1px 5px;
    border-radius: var(--sf-radius-sm);
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    vertical-align: 1px;
    background: var(--sf-tint-2);
    color: var(--sf-muted);
}
/* TWO LABELS, ONE PILL. The table shows MF and puts "Mutual Fund" on the
   hover card. A phone has no hover, and a card has the width, so the
   breakpoint swaps which of the two spans is painted rather than leaving
   a reader on a phone with an abbreviation and no way to resolve it. */
.bq-sf-veh-f { display: none; }
.bq-sf-veh--etf         { background: var(--sf-accent-soft); color: var(--sf-accent); }
.bq-sf-veh--mutual-fund { background: rgba(100, 85, 216, .10); color: var(--sf-violet); }
.bq-sf-veh--uit         { background: rgba(14, 133, 119, .10); color: var(--sf-teal); }
.bq-sf-veh--closed-end  { background: var(--sf-amber-soft); color: var(--sf-amber); }

.bq-sf-name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 12.5px;
    color: var(--sf-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Kept for the cards, where there IS room for a third line and no hover
   to put it behind. Hidden in the table. */
.bq-sf-class { display: none; }

/* empty + loading */
.bq-sf-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 70px 24px;
    text-align: center;
}
.bq-sf-empty strong { font-size: 16px; color: var(--sf-ink); }
.bq-sf-empty span { font-size: 13.5px; color: var(--sf-muted); }
.bq-sf-empty .bq-sf-btn { margin-top: 6px; }

.bq-sf-tablewrap.is-busy .bq-sf-table { opacity: .38; transition: opacity .12s ease; }
.bq-sf-tablewrap.is-busy { pointer-events: none; }

/* NEAR THE TOP, NOT THE MIDDLE. The wrapper is now a full page of rows
   tall whatever it holds, so a spinner centred in it lands ~790px down --
   off the fold, under a table that is already dimmed. It goes where the
   reader is looking: just under the header row. */
.bq-sf-loading {
    position: absolute;
    top: 96px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 6px;
    z-index: 5;
}
.bq-sf-loading span {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--sf-accent);
    animation: bq-sf-bounce 1.1s infinite ease-in-out both;
}
.bq-sf-loading span:nth-child(2) { animation-delay: .14s; }
.bq-sf-loading span:nth-child(3) { animation-delay: .28s; }
@keyframes bq-sf-bounce { 0%, 80%, 100% { transform: scale(.5); opacity: .5; } 40% { transform: scale(1); opacity: 1; } }


/* =====================================================================
   THE HOVER CARD
   ===================================================================== */
/* The same object as .ck-lock-tip in company-KPI and .mp-tip-* in
   metric-pages, and deliberately identical to them: a reader who has
   hovered a KPI table on this site has already learned what this card is.

   LITERAL COLOURS, NOT var(--sf-*), FOR THE SAME REASON THE KPI FILE
   SPELLS OUT: the card is appended to <body>, the tokens are declared on
   .bq-sf, and a var() that resolves nowhere falls back to its
   guaranteed-invalid initial value -- black text, no border, and none of
   the greys. These are the numbers those tokens hold. */
.bq-sf-tip {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 10001;
    width: max-content;
    min-width: 190px;
    max-width: min(340px, calc(100vw - 24px));
    padding: 10px 12px;
    background: #fff;
    border: 1px solid #cfd9e3;
    box-shadow: 0 8px 24px rgba(11, 31, 46, .13);
    font-family: inherit;
    font-size: 12px;
    line-height: 1.45;
    color: #37485a;
    font-variant-numeric: tabular-nums;
    opacity: 0;
    pointer-events: none;
    transform: translateY(3px);
    transition: opacity .13s ease, transform .13s ease;
}
.bq-sf-tip.is-open {
    opacity: 1;
    transform: translateY(0);
}

.bq-sf-tip-name {
    margin-bottom: 2px;
    font-size: 13px;
    font-weight: 700;
    line-height: 1.35;
    color: #0b1f2e;
    overflow-wrap: anywhere;
}
.bq-sf-tip-sub {
    margin: 0 0 8px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.3;
    color: #6b7a89;
    overflow-wrap: anywhere;
}

.bq-sf-tip-line {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
}
.bq-sf-tip-line + .bq-sf-tip-line { margin-top: 5px; }

.bq-sf-tip-k {
    font-size: 11px;
    color: #97a4b2;
    overflow-wrap: anywhere;
}
.bq-sf-tip-v {
    font-size: 12px;
    font-weight: 700;
    color: #0b1f2e;
    white-space: nowrap;
}
.bq-sf-tip-v.is-null { color: #97a4b2; font-weight: 400; }

/* The pill, spelled out. The table prints "MF" because the column is
   108px wide and the word is not the point there; the card has the room
   and is where a reader goes to find out what MF meant. */
.bq-sf-tip .bq-sf-veh {
    display: inline-block;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    background: #f1f3f5;
    color: #6b7a89;
}
.bq-sf-tip .bq-sf-veh--etf         { background: rgba(0, 82, 155, .08);   color: #00529b; }
.bq-sf-tip .bq-sf-veh--mutual-fund { background: rgba(100, 85, 216, .10); color: #6455d8; }
.bq-sf-tip .bq-sf-veh--uit         { background: rgba(14, 133, 119, .10); color: #0e8577; }
.bq-sf-tip .bq-sf-veh--closed-end  { background: rgba(176, 118, 26, .12); color: #b0761a; }

/* The description of a column, under a rule -- the metrics list's own
   text, which is the only place a reader is told that a blank expense
   ratio is not a free fund. */
.bq-sf-tip-note {
    margin-top: 8px;
    padding-top: 7px;
    border-top: 1px solid #eaeff4;
    font-size: 11px;
    line-height: 1.45;
    color: #6b7a89;
}


/* =====================================================================
   PAGER
   ===================================================================== */
.bq-sf-pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    flex-wrap: wrap;
    padding: 18px 0 4px;
}

/* Zero results, or a single page: the nav is emptied rather than removed, and
   an empty flex box still costs its own padding. Collapse it so the empty
   state is not followed by a dead strip. */
.bq-sf .bq-sf-pager:empty {
    display: none;
}

.bq-sf-pager button {
    min-width: 36px;
    height: 36px;
    padding: 0 10px;
    border: 1px solid var(--sf-line-mid);
    background: var(--sf-card);
    border-radius: var(--sf-radius-sm);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--sf-text);
    cursor: pointer;
    transition: all .14s ease;
}
.bq-sf-pager button:hover:not([disabled]) { border-color: var(--sf-accent); color: var(--sf-accent); }
.bq-sf-pager button.is-current {
    background: var(--sf-accent-mid);
    border-color: var(--sf-accent-mid);
    color: #fff;
    cursor: default;
}
.bq-sf-pager button[disabled] { opacity: .4; cursor: not-allowed; }
.bq-sf-pager .bq-sf-gap { color: var(--sf-faint); padding: 0 3px; font-size: 13px; }

/* NO PADLOCK ON A PAGE NUMBER. The gate is real -- the server refuses a
   non-zero offset for a logged-out reader whatever the button does -- but
   advertising it on eleven buttons before anyone has tried to use one
   turns a working table into a wall of locks. The page numbers look
   ordinary; clicking one is what raises the prompt. Same reasoning as the
   Download button. */


/* =====================================================================
   FOOT NOTE
   ===================================================================== */
.bq-sf-foot {
    margin-top: 20px;
    padding: 16px 18px;
    background: var(--sf-tint);
    border: 1px solid var(--sf-line);
    border-radius: var(--sf-radius);
}
.bq-sf-foot p { margin: 0; font-size: 12.5px; line-height: 1.65; color: var(--sf-muted); }
.bq-sf-foot strong { color: var(--sf-ink); }
.bq-sf-foot em { font-style: normal; font-weight: 600; color: var(--sf-text); }


/* =====================================================================
   COLUMN CHOOSER
   ===================================================================== */
.bq-sf-modal {
    position: fixed;
    inset: 0;
    z-index: 100000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.bq-sf-modal[hidden] { display: none; }

.bq-sf-modal-scrim { position: absolute; inset: 0; background: rgba(22, 32, 43, .5); backdrop-filter: blur(2px); }

.bq-sf-modal-box {
    position: relative;
    width: 100%;
    max-width: 720px;
    max-height: min(82vh, 760px);
    display: flex;
    flex-direction: column;
    background: var(--sf-card);
    border: 1px solid var(--sf-line-strong);
    border-radius: var(--sf-radius);
    box-shadow: var(--sf-shadow-lg);
    overflow: hidden;
}

.bq-sf-modal-head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 18px 20px 14px;
    border-bottom: 1px solid var(--sf-line);
}
.bq-sf-modal-head h2 { margin: 0 0 3px; font-size: 17px; font-weight: 700; color: var(--sf-ink); }
.bq-sf-modal-head p { margin: 0; font-size: 12.5px; color: var(--sf-muted); }
.bq-sf-modal-head > div { margin-right: auto; }

.bq-sf-modal-x {
    width: 30px; height: 30px;
    border: 0; border-radius: var(--sf-radius-sm);
    background: var(--sf-tint-2);
    color: var(--sf-muted);
    font-size: 20px; line-height: 1;
    cursor: pointer;
}
.bq-sf-modal-x:hover { background: var(--sf-line-mid); color: var(--sf-ink); }

.bq-sf-modal-search { padding: 12px 20px 0; }
.bq-sf-modal-search input {
    width: 100%;
    padding: 9px 12px;
    font: inherit;
    font-size: 13.5px;
    border: 1px solid var(--sf-line-mid);
    border-radius: var(--sf-radius-sm);
    background: var(--sf-tint);
}
.bq-sf-modal-search input:focus { outline: none; border-color: var(--sf-accent); background: #fff; box-shadow: 0 0 0 3px var(--sf-accent-soft); }

.bq-sf-modal-body { flex: 1 1 auto; overflow-y: auto; padding: 12px 20px 18px; }

.bq-sf-colgroup + .bq-sf-colgroup { margin-top: 16px; }
.bq-sf-colgroup-name {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--sf-faint);
    padding-bottom: 6px;
    border-bottom: 1px solid var(--sf-line);
    margin-bottom: 6px;
}
.bq-sf-colgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 1px 10px; }

.bq-sf-colopt {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-radius: var(--sf-radius-sm);
    font-size: 13px;
    cursor: pointer;
    color: var(--sf-text);
    min-width: 0;
}
.bq-sf-colopt:hover { background: var(--sf-tint-2); }
.bq-sf-colopt input { accent-color: var(--sf-accent); width: 14px; height: 14px; margin: 0; flex: none; }
.bq-sf-colopt span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bq-sf-colopt.is-on { font-weight: 600; color: var(--sf-ink); }

.bq-sf-modal-foot {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 14px 20px;
    border-top: 1px solid var(--sf-line);
    background: var(--sf-tint);
}

.bq-sf-scrim { position: fixed; inset: 0; background: rgba(22, 32, 43, .45); z-index: 99990; }
.bq-sf-scrim[hidden] { display: none; }

/* A toast for the things that need saying but not a modal — a download
   that succeeded, a screen with nothing to export. */
/* THE ONE LINKED VALUE IN THE TABLE.
   Underlined only on hover, because a column of permanently underlined names
   in a dense grid reads as noise; the ticker beside it is what tells a reader
   the name is a destination and not just a longer string. */
.bq-sf .bq-sf-hold {
    color: var(--sf-ink);
    text-decoration: none;
}
.bq-sf .bq-sf-hold:hover { color: var(--sf-accent); text-decoration: underline; }
.bq-sf .bq-sf-hold-tk {
    margin-left: 6px;
    padding: 1px 5px;
    border-radius: var(--sf-radius-sm);
    background: var(--sf-tint-2);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .02em;
    color: var(--sf-muted);
}
.bq-sf .bq-sf-hold:hover .bq-sf-hold-tk { background: var(--sf-accent); color: #fff; }

.bq-sf-toast {
    position: fixed;
    left: 50%;
    bottom: 26px;
    transform: translateX(-50%) translateY(12px);
    z-index: 100001;
    padding: 11px 18px;
    border-radius: 999px;
    background: var(--sf-ink);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    box-shadow: var(--sf-shadow-lg);
    opacity: 0;
    pointer-events: none;
    transition: opacity .2s ease, transform .2s ease;
}
.bq-sf-toast.is-on { opacity: 1; transform: translateX(-50%) translateY(0); }



/* =====================================================================
   ABOUT + THE COMPARISON CLUSTER
   =====================================================================
   Deliberately NOT sharing fund-comparison.css's .bq-fc-qa rules. Both
   stylesheets load together on /fund-comparison, so a shared class name
   defined in two files is two sources of truth for one component and the
   later file silently wins. Same shape, own names, own file.
   ===================================================================== */
.bq-sf-about {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    margin-top: 30px;
    background: var(--sf-card);
    border: 1px solid var(--sf-line-strong);
    border-radius: var(--sf-radius);
    box-shadow: var(--sf-shadow);
    overflow: hidden;
}

.bq-sf-about-side {
    padding: 24px 24px 24px 26px;
    border-right: 1px solid var(--sf-line);
    background: var(--sf-tint);
}
.bq-sf-about-side h2 {
    margin: 0 0 10px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--sf-muted);
}
.bq-sf-about-side p {
    margin: 0 0 14px;
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--sf-text);
}

.bq-sf-about-stats {
    list-style: none;
    margin: 0 0 18px;
    padding: 14px 0 0;
    border-top: 1px solid var(--sf-line);
    display: grid;
    gap: 10px;
}
.bq-sf-about-stats li {
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.bq-sf-about-stats b {
    min-width: 62px;
    font-size: 15px;
    font-weight: 700;
    color: var(--sf-ink);
    font-variant-numeric: tabular-nums;
}
.bq-sf-about-stats span { font-size: 12.5px; color: var(--sf-muted); }

.bq-sf-about-cta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 700;
    color: var(--sf-accent);
    text-decoration: none;
}
.bq-sf-about-cta svg { width: 15px; height: 15px; fill: currentColor; }
.bq-sf-about-cta:hover { text-decoration: underline; }

.bq-sf-about-qa { padding: 6px 26px 8px; }

.bq-sf-qa-item { border-top: 1px solid var(--sf-line); }
.bq-sf-qa-item:first-of-type { border-top: 0; }

/* The whole row is the target, and the marker is ours: the native
   triangle sits on the text baseline and cannot be positioned. */
.bq-sf-qa-item > summary {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 0;
    cursor: pointer;
    list-style: none;
}
.bq-sf-qa-item > summary::-webkit-details-marker { display: none; }
.bq-sf-qa-item > summary h3 {
    margin: 0;
    flex: 1 1 auto;
    font-size: 14.5px;
    font-weight: 700;
    color: var(--sf-ink);
    letter-spacing: -.01em;
}
.bq-sf-qa-item > summary::after {
    content: "";
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    margin-right: 3px;
    border-right: 2px solid var(--sf-faint);
    border-bottom: 2px solid var(--sf-faint);
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .18s ease;
}
.bq-sf-qa-item[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.bq-sf-qa-item > summary:hover h3 { color: var(--sf-accent); }
.bq-sf-qa-item > summary:focus-visible { outline: 2px solid var(--sf-accent); outline-offset: 2px; }

.bq-sf-qa-a { padding: 0 0 15px; }
.bq-sf-qa-a p {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.65;
    color: var(--sf-text);
}
.bq-sf-qa-a strong { color: var(--sf-ink); }

/* FOUR ACROSS, SIXTEEN LONG, FOUR EVEN ROWS -- the same fixed grid the
   comparison page uses, and for the same reason: a free-flowing row of
   sixteen chips ends ragged at every window width and reads as filler
   rather than as a directory. The count is set in bq_fc_popular_pairs(). */
.bq-sf-pairs { margin-top: 30px; }
.bq-sf-pairs > h2 {
    margin: 0 0 14px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--sf-muted);
}
.bq-sf-pairs-list {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
}
.bq-sf-pairs-list a {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 12px 14px;
    background: var(--sf-card);
    border: 1px solid var(--sf-line-strong);
    border-radius: var(--sf-radius);
    text-decoration: none;
}
.bq-sf-pairs-list a:hover { border-color: var(--sf-accent); background: var(--sf-hover); }
.bq-sf-pairs-t { font-size: 13.5px; font-weight: 700; color: var(--sf-ink); }
.bq-sf-pairs-n { font-size: 11.5px; line-height: 1.45; color: var(--sf-muted); }

@media (max-width: 1180px) {
    .bq-sf-pairs-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
    .bq-sf-pairs-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .bq-sf-about { grid-template-columns: minmax(0, 1fr); }
    .bq-sf-about-side {
        border-right: 0;
        border-bottom: 1px solid var(--sf-line);
        padding: 20px;
    }
    .bq-sf-about-qa { padding: 4px 20px 8px; }
}
/* Sixteen links stacked one to a row is a thousand pixels of directory
   between the reader and the footer. Two across, and the one-line note goes
   -- the pair itself is the link text, and it is the half that carries the
   query. Every link stays on the page; only the gloss goes. */
@media (max-width: 560px) {
    .bq-sf-pairs-list { gap: 8px; }
    .bq-sf-pairs-list a { padding: 11px 12px; }
    .bq-sf-pairs-t { font-size: 13px; }
    .bq-sf-pairs-n { display: none; }
}

/* =====================================================================
   RESPONSIVE  —  1180px : narrower rail
   ===================================================================== */
@media (max-width: 1180px) {
    .bq-sf-shell { grid-template-columns: 262px minmax(0, 1fr); gap: 14px; }
    .bq-sf-title { font-size: 26px; }
}


/* =====================================================================
   1024px  —  THE RAIL BECOMES A SHEET
   ---------------------------------------------------------------------
   A 260px column of filters beside a table on a tablet leaves neither
   enough room. Below this the rail slides in over the page from the
   left, the results column takes the full width, and the Filters button
   in the result bar is what opens it.
   ===================================================================== */
@media (max-width: 1024px) {
    .bq-sf-shell { display: block; }

    .bq-sf-rail {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: min(360px, 88vw);
        height: auto;            /* top:0/bottom:0 set it -- see the pane rule */
        max-height: none;
        z-index: 99991;
        border-radius: 0;
        border: 0;
        border-right: 1px solid var(--sf-line-strong);
        box-shadow: var(--sf-shadow-lg);
        transform: translateX(-102%);
        transition: transform .24s cubic-bezier(.4, 0, .2, 1);
        visibility: hidden;
    }
    .bq-sf-rail.is-open { transform: translateX(0); visibility: visible; }

    /* THE SHEET IS A SCROLL CONTAINER, AND IT WAS NOT ONE.
       The rail is a fixed flex column pinned top:0/bottom:0 with a head, a
       body and an Apply footer. The body kept the desktop's `overflow:
       visible`, so on a phone the filter groups below the fold simply could
       not be reached -- there was nothing to scroll.

       min-height:0 IS NOT OPTIONAL. A flex child's min-height defaults to
       `auto`, which refuses to shrink below its content, so the body stays
       full content height and `overflow-y: auto` never has anything to do.
       Without this line the rule looks right and changes nothing.

       A SHEET, NOT A CENTRED MODAL. Phone heights vary, so anything sized
       to the content -- a modal box -- is either taller than a short screen
       or floating in the middle of a tall one. top:0/bottom:0 tracks the
       viewport whatever it is: the head and the Apply button stay put and
       only the filters move, which is also what a reader expects when they
       came from a "Filters" button on the left. */
    .bq-sf-rail-body {
        overflow-y: auto;
        min-height: 0;
        -webkit-overflow-scrolling: touch;
        overscroll-behavior: contain;
    }

    .bq-sf-rail-head { padding: 15px 16px; }
    .bq-sf-rail-close {
        display: block;
        width: 30px; height: 30px;
        border: 0; border-radius: var(--sf-radius-sm);
        background: var(--sf-tint-2);
        color: var(--sf-muted);
        font-size: 20px; line-height: 1;
        cursor: pointer;
    }

    .bq-sf-rail-foot {
        display: block;
        padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
        border-top: 1px solid var(--sf-line);
        background: var(--sf-card);
    }
    .bq-sf-rail-foot .bq-sf-btn { width: 100%; justify-content: center; }

    .bq-sf-filter-toggle {
        display: inline-flex;
        align-items: center;
        gap: 7px;
        margin-left: auto;
        padding: 8px 13px;
        border: 1px solid var(--sf-line-strong);
        background: var(--sf-card);
        border-radius: var(--sf-radius);
        font: inherit;
        font-size: 13px;
        font-weight: 700;
        color: var(--sf-ink);
        cursor: pointer;
        box-shadow: var(--sf-shadow);
    }
    .bq-sf-filter-toggle svg { width: 14px; height: 14px; fill: currentColor; }
    .bq-sf-filter-count {
        min-width: 17px; height: 17px;
        padding: 0 4px;
        border-radius: var(--sf-radius-sm);
        background: var(--sf-active);
        color: #fff;
        font-size: 10.5px;
        line-height: 17px;
        text-align: center;
    }
}


/* =====================================================================
   900px  —  the head stacks
   ===================================================================== */
@media (max-width: 900px) {
    .bq-sf-page { padding: 14px 12px 52px; }
    .bq-sf-head { flex-direction: column; align-items: stretch; gap: 14px; padding-bottom: 14px; }
    .bq-sf-title { font-size: 23px; }
    .bq-sf-lede { font-size: 13.5px; }

    /* Four stamps in an even 2x2 rather than a row that wraps 3 + 1. */
    .bq-sf-stamps {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        width: 100%;
    }
    .bq-sf-stamp { border-left: 0; min-width: 0; padding: 8px 12px; }
    .bq-sf-stamp:nth-child(even) { border-left: 1px solid var(--sf-line); }
    .bq-sf-stamp:nth-child(n + 3) { border-top: 1px solid var(--sf-line); }
}


/* =====================================================================
   700px  —  THE TABLE BECOMES CARDS
   ---------------------------------------------------------------------
   Every <tr> is a card and every <td> a stacked label/value pair in a
   two-column grid. This is the rule that keeps a phone layout EVEN: the
   alternative — label left, value right, one per line — parks every
   number against the right edge and leaves a channel of white down the
   middle, and it makes a card with eight metrics eight lines tall.
   Two columns of pairs fill the card whatever the mix of values and em
   dashes, and the last cell spans both columns when the count is odd so
   a card never ends on a half-empty row.

   WHY 700 AND NOT 860. It was 860, and 768 — the commonest tablet width
   — looked wrong for exactly the reason the cards exist. Two columns
   across a 740px card give each label/value pair 360px to hold "0.03%",
   so every value sits at the left of a wide empty cell and the card ends
   up mostly air. Widening to three or five columns only moves the
   problem: a partially filled last row leaves collapsed tracks on the
   right, which is the same gap in a different place.
   Above 700px the TABLE is the right answer — it fills the width by
   construction and scrolls sideways for the columns that do not fit —
   so the cards now own only the widths where a table genuinely cannot
   work. At 700px two columns give each pair ~330px, and at 390px ~165px:
   comfortable at both ends of the range they cover.
   ===================================================================== */
@media (max-width: 700px) {
    /* The fixed row-count height is a TABLE idea. A card is four lines
       tall and a variable number of them, so the box goes back to fitting
       its content here. */
    .bq-sf-tablewrap {
        background: none;
        border: 0;
        box-shadow: none;
        border-radius: 0;
        overflow: visible;
        height: auto;
        min-height: 300px;
    }

    /* height:auto UNDOES THE ROW-COUNT GEOMETRY. The table sets an exact
       31px on every td so fifty rows come to a predictable box height; a
       card cell is three lines of stacked label-and-value and a card head
       is three lines of its own, so carrying 31px in here clips them into
       one another -- the fund name printed straight through the first
       metric underneath it. */
    .bq-sf-table,
    .bq-sf-table tbody,
    .bq-sf-table tr,
    .bq-sf-table td { display: block; height: auto; }

    .bq-sf-table thead { display: none; }

    /* SIX TRACKS, NOT TWO OR THREE. The visible column count is set by how
       many tracks a cell spans, which is what lets the last row be filled
       exactly at either count — three spans of two, or two spans of three —
       instead of leaving collapsed tracks on the right. See the two blocks
       under this one. */
    .bq-sf-table tr {
        display: grid;
        grid-template-columns: repeat(6, minmax(0, 1fr));
        gap: 11px 12px;
        background: var(--sf-card);
        border: 1px solid var(--sf-line-strong);
        border-radius: 0;
        box-shadow: var(--sf-shadow);
        padding: 13px 14px 14px;
        margin-bottom: 10px;
    }
    .bq-sf-table tbody tr:hover { background: var(--sf-card); }

    /* The card head: ticker, vehicle chip and name, full width. */
    .bq-sf-table .bq-sf-td-id {
        position: static;
        grid-column: 1 / -1;
        /* width:auto IS THE WHOLE FIX. The table pins this column at a hard
           168px, and a grid item with an explicit width uses it INSTEAD of
           the track span it was given -- so `grid-column: 1 / -1` computed
           correctly, reported 1 / -1, and still laid the cell out at 168px
           in a 379px card. The fund name then wrapped at the halfway mark
           with the right half of the card empty. min-width and max-width
           were already reset here; width was the one that was missed. */
        width: auto;
        min-width: 0;
        max-width: none;
        padding: 0 0 11px;
        border: 0;
        border-bottom: 1px solid var(--sf-line);
        background: none;
    }
    .bq-sf-table tbody tr:hover .bq-sf-td-id { background: none; }

    /* THE ONE LINE UNSTACKS HERE. The table compacted the head into a
       single ellipsed line because fifty rows of three lines is a
       scroll; a card is ONE fund and has both the width and the reason
       to print the name and the share class in full. There is also no
       hover on a phone, so anything left to the card would be
       unreachable. */
    .bq-sf-idline { display: block; }
    .bq-sf-tk { font-size: 16px; }
    .bq-sf-veh { margin-left: 6px; font-size: 9.5px; }
    .bq-sf-veh-s { display: none; }
    .bq-sf-veh-f { display: inline; }
    /* .bq-sf-table is on the selector because the table-mode rule that
       hides this is `.bq-sf-table .bq-sf-name` -- two classes. A media
       query contributes NOTHING to specificity, so a bare `.bq-sf-name`
       here loses to it and the fund name stays hidden on the very layout
       that has room for it. */
    .bq-sf-table .bq-sf-name {
        display: -webkit-box;
        margin-top: 3px;
        font-size: 13px;
        white-space: normal;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .bq-sf-class {
        display: block;
        margin-top: 1px;
        font-size: 11px;
        color: var(--sf-faint);
    }

    .bq-sf-table .bq-sf-td {
        padding: 0;
        border: 0;
        white-space: normal;
        text-align: left !important;
        min-width: 0;
    }

    .bq-sf-table .bq-sf-td::before {
        content: attr(data-label);
        display: block;
        margin-bottom: 2px;
        font-size: 9.5px;
        font-weight: 700;
        letter-spacing: .07em;
        text-transform: uppercase;
        color: var(--sf-faint);
        line-height: 1.25;
        /* Two lines maximum, so a long label like "Communication
           Services" cannot push its neighbour's value out of line. */
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    .bq-sf-table .bq-sf-td.is-num { font-size: 15px; font-weight: 700; }
    .bq-sf-table .bq-sf-td:not(.is-num) { font-size: 13.5px; font-weight: 600; color: var(--sf-ink); }

    /* =================================================================
       THE LAST ROW ALWAYS FILLS
       -----------------------------------------------------------------
       A grid whose item count does not divide by its column count leaves
       empty tracks on the right of the final row, and on a card that is
       precisely the "everything lumped left with white down the other
       side" that the card layout exists to avoid. With six tracks the
       leftovers can be widened instead of left blank.

       The arithmetic, since the selectors are not self-explanatory. The
       identity cell is child 1 and spans the row, so M metric cells are
       children 2..M+1 and the last one is child M+1.
         · three across, M ≡ 1 (mod 3): one leftover. M+1 ≡ 2, hence
           :last-child:nth-child(3n+2) — widen it to the full row.
         · three across, M ≡ 2 (mod 3): two leftovers. M+1 ≡ 0, hence
           :last-child:nth-child(3n) for the last and
           :nth-last-child(2):nth-child(3n+2) for the one before it —
           each takes half the row.
         · two across, M odd: M+1 is even, hence
           :last-child:nth-child(even) — the full row.
       ================================================================= */

    /* Two across under 440px: a 165px cell is the narrowest that still
       holds "Communication Services" over a value without either
       clipping. */
    .bq-sf-table .bq-sf-td { grid-column: span 3; }
    .bq-sf-table tr > td:last-child:nth-child(even) { grid-column: span 6; }

    .bq-sf-empty { background: var(--sf-card); border: 1px solid var(--sf-line-strong); border-radius: 0; padding: 48px 20px; }
    .bq-sf-toolbar { flex-wrap: wrap; }
    .bq-sf-search { flex: 1 1 100%; order: 1; }
    .bq-sf-toolbar-right { order: 2; flex: 1 1 auto; }
    .bq-sf-toolbar-right .bq-sf-btn { flex: 1 1 0; justify-content: center; }
}


/* =====================================================================
   441-700px  —  THREE ACROSS
   ---------------------------------------------------------------------
   At 640px two columns give each label/value pair ~295px to hold "0.03%",
   which is the same wasted-cell problem the table had at 768. Three
   across brings a cell back to ~195px, and the two rules below widen the
   final row's leftovers so it still ends flush.
   ===================================================================== */
@media (min-width: 441px) and (max-width: 700px) {
    .bq-sf-table .bq-sf-td { grid-column: span 2; }

    /* one leftover -> full row */
    .bq-sf-table tr > td:last-child:nth-child(3n + 2) { grid-column: span 6; }

    /* two leftovers -> half a row each */
    .bq-sf-table tr > td:last-child:nth-child(3n) { grid-column: span 3; }
    .bq-sf-table tr > td:nth-last-child(2):nth-child(3n + 2) { grid-column: span 3; }

    /* ...and the two-across rule must not also fire here. */
    .bq-sf-table tr > td:last-child:nth-child(even):not(:nth-child(3n)):not(:nth-child(3n + 2)) { grid-column: span 2; }
}


/* =====================================================================
   560px  —  small phones
   ===================================================================== */
@media (max-width: 560px) {
    .bq-sf-page { padding: 12px 10px 48px; }
    .bq-sf-title { font-size: 21px; }
    .bq-sf-lede { font-size: 13px; }
    .bq-sf-eyebrow { font-size: 10px; }

    .bq-sf-table tr { gap: 10px 10px; padding: 12px 12px 13px; }
    .bq-sf-table .bq-sf-td.is-num { font-size: 14.5px; }

    .bq-sf-count strong { font-size: 15px; }
    .bq-sf-foot { padding: 13px 14px; }
    .bq-sf-foot p { font-size: 12px; }

    .bq-sf-pager button { min-width: 34px; height: 34px; padding: 0 8px; font-size: 12.5px; }

    .bq-sf-modal { padding: 0; align-items: flex-end; }
    .bq-sf-modal-box { max-width: none; max-height: 92vh; border-radius: 0; }
    .bq-sf-modal-foot .bq-sf-btn { flex: 1 1 0; justify-content: center; }
    .bq-sf-colgrid { grid-template-columns: 1fr; }
}

/* 380px — the narrowest phones still get two columns, because one column
   of stacked pairs is a very long card. Only the type gets smaller. */
@media (max-width: 380px) {
    .bq-sf-table .bq-sf-td.is-num { font-size: 13.5px; }
    .bq-sf-table .bq-sf-td:not(.is-num) { font-size: 12.5px; }
    .bq-sf-table .bq-sf-td::before { font-size: 9px; letter-spacing: .05em; }
    .bq-sf-stamp-v { font-size: 12px; }
}

@media (prefers-reduced-motion: reduce) {
    .bq-sf *, .bq-sf *::before, .bq-sf *::after {
        animation-duration: .001ms !important;
        transition-duration: .001ms !important;
    }
}
