/* frb-editorial.css — the two faces the editorial pages are set in.
 *
 * Feerebu ships Outfit and JetBrains Mono to the browser, and 241 families to
 * the PDF renderer in backend/assets/fonts. Syne and Instrument Serif were
 * already in that bundle, already licensed and already vendored — they were
 * simply not reachable from a page. These six files are those two families,
 * copied to the web side, with their OFL text beside them.
 *
 * SELF-HOSTED ON PURPOSE. The CSP is `font-src 'self' data: fonts.gstatic.com`,
 * and the fetch tool's own reason applies here too: a face pulled at render
 * time works until the host has no egress, and then a page set in a typeface
 * arrives in a different one, silently.
 *
 * WHERE THEY ARE USED
 *   Syne              display — headings, the wordmark, the oversized numeral
 *   Instrument Serif  the italic accent, and only that
 *   JetBrains Mono    labels, eyebrows, body (already shipped, not redeclared)
 *
 * Outfit stays the product's font. This sheet is linked by the editorial pages
 * only; nothing else in the product changes typeface because of it.
 *
 * NO PADDED FACES — why two files in the backend bundle were left behind.
 * Syne ships no italic cut and Instrument Serif ships no bold one. The PDF
 * bundle papered over both by duplicating the regular: syne-400i.woff2 is
 * byte-identical to syne-400.woff2, and instrumentserif-700.woff2 to its own
 * 400 (md5-checked, not assumed). Declaring those as real faces is worse than
 * leaving them out. A browser TRUSTS an @font-face and does not synthesise on
 * top of it, so `font-style:italic` against an upright file renders upright —
 * measured in Chromium: a declared-italic-pointing-at-upright span came back
 * unslanted, while the same span with no italic declared was sheared by the
 * engine. Omitting them means italic Syne and bold Instrument Serif get a
 * synthetic slant and a synthetic bold, which is the honest degrade.
 * instrumentserif-400i.woff2 IS a genuine cut (distinct md5) — that one is the
 * italic accent this design is actually set in, and it is declared below.
 */

/* ── Syne — display ───────────────────────────────────────────────────────── */
@font-face {
  font-family: 'Syne';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/editorial/syne-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Syne';
  font-style: normal;
  /* The bundle carries 400 and 700. 700 is declared across 700–800 so a
     `font-weight:800` heading synthesises from the bold rather than falling
     back to the regular, which is what makes a display line look thin. */
  font-weight: 700 800;
  font-display: swap;
  src: url('../fonts/editorial/syne-700.woff2') format('woff2');
}
/* No Syne italic is declared, deliberately — see NO PADDED FACES below. */

/* ── Instrument Serif — the italic accent ─────────────────────────────────── */
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/editorial/instrumentserif-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/editorial/instrumentserif-400i.woff2') format('woff2');
}
/* No Instrument Serif bold is declared, deliberately — see NO PADDED FACES. */

/* ── the roles, as tokens ─────────────────────────────────────────────────── */
/* Declared here rather than in each page so an editorial page states a ROLE
   and never a family name. Real fallback stacks: a missing woff2 must not drop
   a heading to Times. */
:root {
  --frb-ed-display: 'Syne', 'Outfit', system-ui, -apple-system, sans-serif;
  --frb-ed-serif: 'Instrument Serif', Georgia, 'Times New Roman', serif;
  --frb-ed-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ── the title scale ──────────────────────────────────────────────────────── */
/* ONE SIZE PER TIER, because the alternative is what was there: eleven page
   titles at five different sizes and two different weights — 74px on the two
   internal pages, 58 on analytics, 51 on the style guide and portals, 48 on the
   legal pages and notifications, 40 at weight 700 on the account pages, and 28
   on plans, which was not a choice at all but frb-compat.css's --frb-app-title-
   size winning because that page never set the `title` opt-out.

   TWO TIERS, and the difference between them is real rather than decorative:

   --frb-ed-title       a PAGE HEAD. The page sits under the shell's breadcrumb
                        band, the title names it, and the content starts right
                        below. Every such page is now this size.
   --frb-ed-title-hero  a HERO. The page opens on a full-bleed statement with
                        nothing above it — home, index, the version history and
                        the roadmap. It gets the scale that makes a hero a hero.

   A page picks a tier. It does not pick a number. */
:root {
    --frb-ed-title: clamp(2.1rem, 4vw, 3.1rem);
    --frb-ed-title-hero: clamp(2.6rem, 6vw, 4.6rem);
    --frb-ed-title-weight: 800;
    --frb-ed-title-tracking: -.04em;
    --frb-ed-title-leading: .96;
    /* The accent's size relative to the name. It was 1.04em on four pages and
       1.06em on two — a 3px difference at 50px, small enough to survive every
       eyeball check and visible the moment two titles are measured against
       each other with the same string in them. */
    --frb-ed-accent-size: 1.05em;
}

/* ── the cell surface ─────────────────────────────────────────────────────── */
/* A cell that shares a 1px edge with its neighbour has to be OPAQUE, or the
 * rule colour beneath reads through and every tile turns the colour of the
 * line. The obvious way to get opacity is the solid ground — and that is what
 * the first pass did, which worked and flattened the glass off every page it
 * touched. Black is opaque; it is also black.
 *
 * These do the same job with the light left in: the translucent white the glass
 * surfaces already use, composited over the solid ground rather than over
 * whatever happens to be behind it. Opaque for the hairline, lifted for the
 * look. --frb-cell-hi is the same surface for hover and selected states.
 *
 * Declared here so the pages taking this treatment share one definition instead
 * of each carrying a copy — which is the drift this whole pass exists to undo.
 */
:root {
  --frb-cell: linear-gradient(0deg, rgba(255,255,255,.045), rgba(255,255,255,.045))
              var(--bg-solid, #000);
  --frb-cell-hi: linear-gradient(0deg, rgba(255,255,255,.085), rgba(255,255,255,.085))
                 var(--bg-solid, #000);
}
.light-mode {
  --frb-cell: linear-gradient(0deg, rgba(255,255,255,.75), rgba(255,255,255,.75))
              var(--bg-solid, #f3f4f6);
  --frb-cell-hi: linear-gradient(0deg, rgba(255,255,255,1), rgba(255,255,255,1))
                 var(--bg-solid, #f3f4f6);
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE EDITORIAL STRUCTURE — moved here out of home.html, unchanged.

   These are the classes that make the codefolio language a LAYOUT rather than
   a set of fonts: the section head with its numeral at the margin, the row
   grid with a vertical numeral spine and a square arrow cell, the welded stat
   strip, the chips, the hairline footer. home.html had all of it and every
   other page had none of it, so every other page got type and geometry and
   stopped there — which is exactly as far as a font change goes.

   Written once here for the same reason frb-auth.css is written once for six
   pages and frb-legal.css for two. A page states a ROLE and gets the whole
   structure; nothing is re-typed, so nothing can drift.

   ONE CHANGE ON THE WAY OVER, and it is the one already settled earlier in
   this pass: .ed-stat painted itself with --bg-solid, which is opaque and is
   also pure black, and flattened the glass off the strip. It now uses
   --frb-cell — the same translucent white composited over the solid ground,
   declared at the top of this file. Opaque for the hairline, lifted for the
   look.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ONE GUTTER, ONE EDGE. 1320px centred put the hero in a column with ~200px of
   dead ground either side on a 1711px screen, while portals, analytics, the
   legal pages, the style guide and all 24 hubs run to a 40px gutter. That was
   the third different width in three pages the last time it came up, and it is
   the same answer now: the page runs the width of the window and the sections'
   own padding is the gutter.

   The hero and every .ed-sec already carry clamp(20px, 4vw, 56px) of side
   padding, so removing the cap does not push anything to the screen edge — it
   hands the gutter to the rule that was always drawing it. */
.ed-wrap { max-width: none; width: 100%; margin: 0; }

/* A hairline that is the same hairline everywhere on the page. */
.ed-rule { border-top: 1px solid var(--glass-border-color); }

/* ── hero ────────────────────────────────────────────────────────────────── */
.ed-hero {
    position: relative;
    padding: clamp(72px, 11vw, 132px) clamp(20px, 4vw, 56px) clamp(48px, 6vw, 76px);
    overflow: hidden;
}
/* The stroke numeral. Decorative, so it is aria-hidden and cannot be selected
   or dragged into the text flow. */
.ed-hero-num {
    position: absolute; right: -.12em; bottom: -.18em;
    font-family: var(--frb-ed-display);
    font-size: clamp(200px, 30vw, 460px); font-weight: 800; line-height: 1;
    letter-spacing: -.05em;
    color: transparent;
    /* Its own stroke, not the hairline token: at rgba(255,255,255,.10) the
       numeral was invisible on every theme. Tied to the accent so it stays
       part of the palette, and kept under 20% so it never competes. */
    -webkit-text-stroke: 1px color-mix(in srgb, var(--accent-primary) 26%, transparent);
    pointer-events: none; user-select: none;
}
.ed-status {
    display: flex; align-items: center; gap: 10px;
    font-size: 11px; letter-spacing: .15em; text-transform: uppercase;
    color: var(--text-secondary); margin-bottom: clamp(28px, 4vw, 46px);
}
.ed-dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--accent-primary);
    box-shadow: 0 0 10px var(--accent-primary);
    animation: edBreathe 2.6s ease-in-out infinite;
}
@keyframes edBreathe { 0%,100% { opacity:1; transform:scale(1) } 50% { opacity:.4; transform:scale(.7) } }

.ed-title {
    font-family: var(--frb-ed-display);
    font-size: clamp(2.9rem, 8.4vw, 7.4rem);
    font-weight: 800; line-height: .92; letter-spacing: -.04em;
    margin: 0 0 clamp(26px, 3.4vw, 40px); text-wrap: balance;
}
/* `.outline` in the reference: `-webkit-text-stroke: 2px; color: transparent`.
   GUARDED, which the reference is not — `color:transparent` without a stroke to
   draw it is an invisible line of the headline, so the fallback has to be the
   solid word, not nothing. */
.ed-title .ed-out { display: block; }
@supports (-webkit-text-stroke: 1px black) {
    .ed-title .ed-out {
        -webkit-text-stroke: 2px var(--text-primary);
        color: transparent;
    }
}
.ed-title .ed-em {
    display: block;
    font-family: var(--frb-ed-serif);
    font-style: italic; font-weight: 400;
    font-size: clamp(3.1rem, 9vw, 8rem);
    color: var(--accent-text);
    letter-spacing: -.01em;
}
.ed-hero-foot {
    display: grid; grid-template-columns: minmax(0,1fr) auto;
    gap: clamp(20px, 3vw, 48px); align-items: end;
}
.ed-lede {
    font-size: 13px; line-height: 1.95; color: var(--text-secondary);
    max-width: 46ch; margin: 0;
}
.ed-lede strong { color: var(--text-primary); font-weight: 400; }
.ed-acts { display: flex; gap: 10px; flex-wrap: wrap; }

/* Buttons. Shape and motion are local to the editorial treatment; the colours
   are the product's. */
.ed-btn {
    display: inline-flex; align-items: center; gap: 10px;
    font-family: var(--frb-ed-mono); font-size: 12px;
    letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
    padding: 14px 26px; border: 1px solid var(--glass-border-color);
    color: var(--text-primary);
    transition: border-color var(--frb-dur-base) var(--frb-ease),
                transform var(--frb-dur-base) var(--frb-ease),
                box-shadow var(--frb-dur-base) var(--frb-ease);
}
.ed-btn:hover { border-color: var(--accent-primary); }
.ed-btn-go {
    background: var(--accent-primary); border-color: var(--accent-primary);
    color: var(--btn-text, #000); font-weight: 500;
}
/* `.btn-p:hover { box-shadow: 6px 6px 0 var(--red) }` — a hard offset BLOCK,
   not a soft glow. --accent-glow is translucent, so the offset read as a blur
   rather than as a second solid shape behind the button. The block lands in the
   ink colour: red is --danger here and means something. */
.ed-btn-go:hover { transform: translate(-3px,-3px); box-shadow: 6px 6px 0 var(--text-primary); }
.ed-btn:focus-visible {
    outline: var(--frb-focus-width) solid var(--accent-primary);
    outline-offset: var(--frb-focus-offset);
}

/* ── ticker ──────────────────────────────────────────────────────────────── */
.ed-ticker {
    border-top: 1px solid var(--glass-border-color);
    border-bottom: 1px solid var(--glass-border-color);
    background: var(--card-bg); overflow: hidden; padding: 12px 0;
}
.ed-ticker-track { display: flex; width: max-content; animation: edTick 30s linear infinite; }
.ed-tick {
    white-space: nowrap; font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
    color: var(--text-secondary); padding: 0 30px;
    border-right: 1px solid var(--glass-border-color);
}
.ed-tick.on { color: var(--accent-text); }
@keyframes edTick { from { transform: translateX(0) } to { transform: translateX(-50%) } }

/* ── stats ───────────────────────────────────────────────────────────────── */
/* `.about-sg` / `.about-sc` / `.sn` / `.sl`. Four across the full width rather
   than the reference's 2x2, which is 2x2 only because it sits in a narrow
   column there. Every figure is counted from the repo — 101 files under
   frontend/apps, the 24 hubs PAGE-INVENTORY.md lists, the 13 charts the
   analytics row below already claims, and the four themes in frb-tokens. */
.ed-stats {
    display: grid; grid-template-columns: repeat(4, minmax(0,1fr));
    gap: 1px; background: var(--glass-border-color);
    border-bottom: 1px solid var(--glass-border-color);
}
.ed-stat { background: var(--frb-cell, var(--bg-solid, #000)); padding: clamp(22px,3vw,34px) clamp(18px,2.4vw,30px); }
.ed-stat-n {
    font-family: var(--frb-ed-display); font-weight: 800; line-height: 1;
    font-size: clamp(1.9rem, 3.4vw, 2.9rem); letter-spacing: -.03em;
    color: var(--accent-text);
}
.ed-stat-l {
    font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
    color: var(--text-secondary); margin-top: 8px;
}

/* ── sections ────────────────────────────────────────────────────────────── */
.ed-sec { padding: clamp(56px, 8vw, 104px) clamp(20px, 4vw, 56px); }
.ed-sec-head {
    /* `.sh { justify-content: space-between }` — the index sits at the margin
       and the title runs from it, rather than the two sitting as one clump. */
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 18px; margin-bottom: clamp(32px, 4.5vw, 58px);
}
.ed-sec-n { font-size: 11px; letter-spacing: .15em; color: var(--text-secondary); }
.ed-sec-t {
    font-family: var(--frb-ed-display);
    font-size: clamp(1.9rem, 4vw, 3.4rem); font-weight: 800;
    line-height: .98; letter-spacing: -.035em; margin: 0;
}
.ed-sec-t em {
    font-family: var(--frb-ed-serif); font-style: italic;
    font-weight: 400; color: var(--accent-text);
}

/* Rows, not cards. A card is a box with a shadow; these share edges, which is
   what makes a set read as a set. */
.ed-rows { border: 1px solid var(--glass-border-color); }
.ed-row {
    display: grid; grid-template-columns: 74px minmax(0,1fr) minmax(0,1.35fr);
    border-bottom: 1px solid var(--glass-border-color);
    transition: background var(--frb-dur-fast) var(--frb-ease);
    text-decoration: none; color: inherit;
}
.ed-row:last-child { border-bottom: 0; }
.ed-row:hover { background: var(--frb-surface-hover); }
.ed-row:focus-visible {
    outline: var(--frb-focus-width) solid var(--accent-primary);
    outline-offset: -2px;
}
.ed-row-n {
    /* `.pnum` in the reference is set on its side. It is what makes the number
       track read as a spine down the list rather than a column of captions. */
    writing-mode: vertical-rl;
    display: flex; align-items: center; justify-content: center; padding: 26px 0;
    border-right: 1px solid var(--glass-border-color);
    font-size: 11px; letter-spacing: .1em; color: var(--text-secondary);
    transition: color var(--frb-dur-fast) var(--frb-ease);
}
.ed-row:hover .ed-row-n { color: var(--accent-text); }
.ed-row-m { padding: 28px 26px; border-right: 1px solid var(--glass-border-color); }
.ed-row-ic { font-size: 18px; color: var(--accent-text); margin-bottom: 14px; }
.ed-row-t {
    font-family: var(--frb-ed-display); font-size: 1.35rem; font-weight: 700;
    letter-spacing: -.025em; line-height: 1.05; margin: 0 0 6px;
}
.ed-row-s { font-size: 11px; color: var(--text-secondary); letter-spacing: .04em; }
.ed-row-r {
    padding: 28px 26px; display: flex; flex-direction: column;
    justify-content: center; gap: 18px;
}
/* Only a row that HAS a chip pushes its two children apart. Without this the
   descriptions in section 01 — which carry no chip — sat pinned to the top of a
   tall cell with the space stranded underneath them. */
.ed-row-r:has(.ed-chip) { justify-content: space-between; }
.ed-row-d { font-size: 12.5px; line-height: 1.85; color: var(--text-secondary); margin: 0; }
.ed-chip {
    align-self: flex-start; font-size: 10px; letter-spacing: .11em;
    text-transform: uppercase; padding: 5px 11px;
    border: 1px solid var(--glass-border-color); color: var(--text-secondary);
}
.ed-chip.live { border-color: var(--accent-primary); color: var(--accent-text); }

/* `.paction` + `.p-arrow`: a square bordered glyph in its own cell, which
   travels and takes the accent when the row is hovered. It is only on rows that
   are links — section 01 describes, section 02 navigates, and an arrow on a row
   that goes nowhere is a promise the page does not keep. */
.ed-row-go {
    display: grid; place-items: center; padding: 26px;
    border-left: 1px solid var(--glass-border-color);
}
.ed-arrow {
    width: 42px; height: 42px; display: grid; place-items: center;
    border: 1px solid var(--glass-border-color);
    color: var(--text-secondary); font-size: 13px;
    transition: transform var(--frb-dur-base) var(--frb-ease),
                color var(--frb-dur-base) var(--frb-ease),
                border-color var(--frb-dur-base) var(--frb-ease);
}
.ed-row:hover .ed-arrow {
    transform: translate(3px, -3px);
    color: var(--accent-text); border-color: var(--accent-primary);
}
/* The link rows carry a fourth track; the descriptive ones keep three. */
.ed-rows-go .ed-row { grid-template-columns: 74px minmax(0,1fr) minmax(0,1.35fr) 110px; }

/* ── footer ──────────────────────────────────────────────────────────────── */
.ed-foot {
    border-top: 1px solid var(--glass-border-color);
    padding: 22px clamp(20px, 4vw, 56px);
    display: flex; justify-content: space-between; align-items: center;
    gap: 16px; flex-wrap: wrap;
}
.ed-foot span, .ed-foot a {
    font-size: 11px; letter-spacing: .08em; color: var(--text-secondary); text-decoration: none;
}
.ed-foot a:hover { color: var(--accent-text); }

/* ── reveal ──────────────────────────────────────────────────────────────── */
.ed-rv { opacity: 0; transform: translateY(26px); transition: opacity .7s var(--frb-ease), transform .7s var(--frb-ease); }
.ed-rv.in { opacity: 1; transform: none; }

/* The first frame is what a share card and a skimming reader both get, so the
   hero is never parked at opacity 0 waiting on an observer. */
@media (prefers-reduced-motion: reduce) {
    .ed-rv { opacity: 1; transform: none; transition: none; }
    .ed-dot, .ed-ticker-track { animation: none; }
}

/* ── narrow ──────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
    .ed-hero-foot { grid-template-columns: 1fr; align-items: start; }
    /* Two columns, three children. Without explicit placement the third one
       wraps into an implicit row IN COLUMN 1 — the 52px numeral track — and a
       paragraph in 52px wraps one character per line. It made each row ~4,600px
       tall and the page 13,862px. The numeral spans instead, and the other two
       stack in the content column. */
    .ed-row { grid-template-columns: 52px minmax(0,1fr); }
    .ed-row-n { grid-column: 1; grid-row: 1 / span 2; padding: 20px 0; align-content: start; }
    .ed-row-m { grid-column: 2; grid-row: 1; border-right: 0; padding: 22px 18px; }
    .ed-row-r { grid-column: 2; grid-row: 2; border-top: 1px solid var(--glass-border-color);
                padding: 18px 18px 22px; }
    /* The arrow's own track does not fit beside a 52px numeral column, and the
       whole row is the tap target on a phone anyway. */
    .ed-rows-go .ed-row { grid-template-columns: 52px minmax(0,1fr); }
    .ed-row-go { display: none; }
    .ed-hero-num { font-size: clamp(160px, 46vw, 300px); }
    /* 2x2 — the reference's own shape, and four across a 390px screen gives
       each figure about 90px. */
    .ed-stats { grid-template-columns: repeat(2, minmax(0,1fr)); }
    .ed-title .ed-out { -webkit-text-stroke-width: 1.5px; }
}
