/*! frb-hub-editorial.css — the codefolio treatment for the 24 section hubs.
 *
 * A hub is a tile grid you pass THROUGH — academics/career.html,
 * business/marketing.html, devs/github.html and twenty-one more. That is the
 * same kind of page as portals.html, which took this treatment in the first
 * batch, so a hub gets the same one. The 77 tools under apps/ are working
 * surfaces and are deliberately not in scope: an app's own dense layout is the
 * thing a person came to use, and the editorial voice has no business
 * overriding it.
 *
 * SCOPED UNDER body.frb-hub, WHICH IS NOT OPTIONAL. .app-card, .app-grid,
 * .app-title and .app-desc are the shared tile vocabulary of 28+ pages,
 * including every one of those 77 tools. An unscoped `.app-card {
 * border-radius: 0 }` here would square tiles across the whole product from a
 * sheet named after the hubs. Same rule as frb-account.css, and the 77 are
 * measured alongside the 24 to prove the scoping holds.
 *
 * A SECOND SHEET RATHER THAN MORE OF frb-hub.css, for two reasons. frb-hub.css
 * is a byte-for-byte extraction of a block sixteen hubs carried inline, and its
 * whole contract is that it changed nothing — appending a treatment would break
 * that. And it is linked BEFORE the design system on those sixteen, so a rule
 * in it loses every tie to frb-compat and frb-shell. This one is linked last,
 * after frb-shell.css, where the design system's own comment says a sheet has
 * to sit to win.
 *
 * THE OTHER EIGHT. Only 16 of the 24 link frb-hub.css; the rest still carry
 * ~160-210 lines of the same block inline. That duplication is not this file's
 * problem to solve and is left alone — but it IS the reason this treatment is
 * linked from all 24 individually rather than written into the shared sheet,
 * because a treatment in frb-hub.css would have reached sixteen of them.
 */

/* ── the page's own voice ─────────────────────────────────────────────────── */
/* Every hub title is <h1 class="mb-1 display-5"> inside .module-header — the
   same structure profile.html and dev_profile.html use, which is why this
   matches on structure rather than on a class none of them carry.

   `fw-bold` was removed from all 24 headings rather than fought: Bootstrap
   ships it as font-weight:700!important, no specificity reaches it, and the
   design system owns the weight now. */
body.frb-hub .module-header h1,
body.frb-hub .page-title {
    font-family: var(--frb-ed-display, 'Syne', 'Outfit', sans-serif);
    font-size: var(--frb-ed-title);
    font-weight: var(--frb-ed-title-weight);
    letter-spacing: var(--frb-ed-title-tracking);
    line-height: var(--frb-ed-title-leading);
}
body.frb-hub .module-header h1 em,
body.frb-hub .page-title em {
    font-family: var(--frb-ed-serif, Georgia, 'Times New Roman', serif);
    font-style: italic;
    font-weight: 400;
    font-size: var(--frb-ed-accent-size);
    /* natural metrics — the display face's tracking is wrong for a serif italic */
    letter-spacing: normal;
    color: var(--accent-text, var(--accent-primary));
}
body.frb-hub .module-header h1 + div,
body.frb-hub .page-sub {
    font-family: var(--frb-ed-mono, 'JetBrains Mono', ui-monospace, monospace);
    font-size: 12.5px;
    line-height: 1.75;
}

/* ── the tiles ────────────────────────────────────────────────────────────── */
/* The same move portals.html made: cells share edges instead of floating apart,
   so a category reads as one object rather than as fourteen cards. The gap IS
   the hairline — 1px of the rule colour showing between opaque cells.

   THE ROUNDED TILES ARE NOT GONE, they are a VIEW. portals.html carries them as
   a sixth mode in its view switcher beside mosaic, grid, command, deck and
   terminal, so the two shapes are a choice a reader makes rather than one
   replacing the other. A hub has no switcher of its own, so it shows the shape
   the portal page opens on. */
body.frb-hub .app-grid {
    gap: 1px;
    background: var(--glass-border-color, rgba(127,127,127,.18));
    border: 1px solid var(--glass-border-color, rgba(127,127,127,.18));
    padding: 0;
}
/* Opaque or the rule reads through every tile — but --frb-cell rather than
   --bg-solid, which is opaque and is also pure black and flattens the glass off
   the whole grid. See frb-editorial.css. */
body.frb-hub .app-grid > .app-card {
    background: var(--frb-cell);
    border: 0;
    border-radius: 0;
    box-shadow: none;
}
body.frb-hub .app-grid > .app-card:hover {
    background: var(--frb-cell-hi);
    transform: none;
}

/* The type inside a tile. The title is a name, the description is reading
   matter, and they should not read as the same kind of thing. */
body.frb-hub .app-card .app-title {
    font-family: var(--frb-ed-display, 'Syne', 'Outfit', sans-serif);
    font-weight: 700;
    letter-spacing: -.02em;
}
body.frb-hub .app-card .app-desc {
    font-family: var(--frb-ed-mono, 'JetBrains Mono', ui-monospace, monospace);
    line-height: 1.7;
}
/* The status pills stay pills — they are labels, not controls, and that call
   was already made for the notification counts and the filter chips. Only
   their type joins the system. */
body.frb-hub .status-badge {
    font-family: var(--frb-ed-mono, 'JetBrains Mono', ui-monospace, monospace);
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: .16em;
}

/* The arrow cell, as on portals: the tile's content stays together at the top
   and a footer mark takes the slack. Generated content, so it stays out of the
   accessibility tree — the tile is already a link and reads as one. */
body.frb-hub .app-grid > .app-card::after {
    content: '\2197';
    margin-top: auto;
    align-self: flex-start;
    width: 32px; height: 32px;
    display: grid; place-items: center;
    border: 1px solid var(--glass-border-color, rgba(127,127,127,.18));
    color: var(--text-secondary);
    font-size: 12px; line-height: 1;
    transition: transform .25s var(--frb-ease, ease),
                color .25s var(--frb-ease, ease),
                border-color .25s var(--frb-ease, ease);
}
body.frb-hub .app-grid > .app-card:hover::after {
    transform: translate(3px, -3px);
    color: var(--accent-text, var(--accent-primary));
    border-color: var(--accent-primary);
}
/* A locked tile goes nowhere, so it gets no arrow — an arrow on a tile that
   does not open is a promise the page does not keep. */
body.frb-hub .app-grid > .app-card.locked::after { content: none; }

@media (prefers-reduced-motion: reduce) {
    body.frb-hub .app-grid > .app-card:hover::after { transform: none; }
}
