/* Objective Dynamix -- public site.
 *
 * HOUSE STYLE, BEFORE YOU CHANGE ANYTHING HERE:
 *   docs/standards/MARKETING_AND_SCOPE.md
 * It governs the layout as well as the words -- the display hero, one idea
 * per section, figures as evidence rather than decoration, and two accents
 * with one job each. Rules 11 to 14.
 *
 * Four static brochure pages. No framework, no build step, no JavaScript:
 * the whole public side is files Apache can serve out of a docroot, which is
 * the separation ``docs/marketing/web-SITE-NOTES.md`` §2 asks for. A visitor
 * to these pages touches no Flask route, no session and no database.
 *
 * ---------------------------------------------------------------------------
 * Where the colours come from
 *
 * The logo is the source. ``objectivedynamix-logo-dark.svg`` is drawn in two
 * colours and only two -- #0B1320 behind, #EEF1F4 in front -- so those are
 * --bg and --ink here rather than something chosen to sit near them. The
 * site notes say that if the logo's colours differ from the old homepage's,
 * the site moves to the logo and not the reverse; this is that move.
 *
 * The logo supplies no accent, so the accents are carried in from the
 * authenticated side. --accent is the blue of the MainBoard's title lozenge
 * family and of the method note's own figures; --accent-2 is the MainBoard's
 * subtitle teal (`--mb-accent-subtitle`), used only as the second series in a
 * figure. Two accents, each with one job, is the whole of the colour system.
 *
 * ---------------------------------------------------------------------------
 * Dark and light
 *
 * Dark is the default because the logo is. Light is a `prefers-color-scheme`
 * override, as the old homepage had. Every colour in the page is a variable
 * so the override is a block of re-declarations and nothing else -- there is
 * no second set of rules that can fall out of step with the first.
 *
 * Figures cannot follow the variables: they are separate SVG files loaded
 * with <img>, and an <img> SVG is a document of its own that cannot see this
 * stylesheet. So `scripts/make_site_figures.py` writes each figure twice, and
 * the pages pick between them with <picture><source media="..."> -- the one
 * mechanism that works without JavaScript and without inlining 50 kB of
 * matplotlib markup into every page.
 * ------------------------------------------------------------------------ */

/* Fonts, self-hosted.
 *
 * They used to come from Google Fonts with an @import. Served from here
 * instead, which means a visitor to the public site makes no request to a
 * third party at all — nothing about who reads this page goes anywhere but
 * our own server.
 *
 * Downloaded from Google Fonts, latin subset only; both are SIL Open Font
 * License, which permits this. Schibsted Grotesk is a single variable file
 * covering 400–900, so one 46 kB download serves every weight the site uses.
 * IBM Plex Mono is two static files. 157 kB in total, against four requests
 * to two other domains.
 *
 * `font-display: swap` means text is readable in a fallback face while the
 * real one arrives, rather than invisible.
 */
@font-face {
    font-family: 'Schibsted Grotesk';
    src: url('fonts/SchibstedGrotesk-variable.woff2') format('woff2-variations'),
         url('fonts/SchibstedGrotesk-variable.woff2') format('woff2');
    font-weight: 400 900;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'IBM Plex Mono';
    src: url('fonts/IBMPlexMono-400.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'IBM Plex Mono';
    src: url('fonts/IBMPlexMono-500.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

:root {
    --bg: #0B1320;
    --bg-raised: #111C2C;
    --bg-sunken: #070E18;
    --ink: #EEF1F4;
    --ink-muted: #9AA7B8;
    --ink-faint: #6B7A8D;
    --rule: #24344A;
    --accent: #5B9DD9;
    --accent-2: #4FD1C5;
    --accent-ink: #0B1320;

    /* Prose is held to a measure rather than to the container width. A line
       of 110 characters is the single most common reason a page of this kind
       is not read to the end. */
    --measure: 36rem;
    --page: 70rem;

    --sans: 'Schibsted Grotesk', 'IBM Plex Sans', -apple-system,
            'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --mono: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Menlo, monospace;
}

@media (prefers-color-scheme: light) {
    :root {
        --bg: #FFFFFF;
        --bg-raised: #F4F6F9;
        --bg-sunken: #EDF1F6;
        --ink: #0B1320;
        --ink-muted: #4A5768;
        --ink-faint: #7B8899;
        --rule: #DDE3EB;
        --accent: #2F5A85;
        --accent-2: #1B7F76;
        --accent-ink: #FFFFFF;
    }
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--sans);
    font-size: 17px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* Skip link. Four pages with an identical masthead means a keyboard or screen
   reader user tabs past the same five links on every one of them. */
.skip {
    position: absolute;
    left: -9999px;
}
.skip:focus {
    left: 1rem;
    top: 1rem;
    z-index: 10;
    padding: 0.5rem 0.9rem;
    background: var(--accent);
    color: var(--accent-ink);
    border-radius: 4px;
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--ink); }

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* ---------------------------------------------------------------------------
 * Masthead
 * ------------------------------------------------------------------------ */

.masthead {
    border-bottom: 1px solid var(--rule);
}

.masthead-inner {
    max-width: var(--page);
    margin: 0 auto;
    padding: 1.1rem 1.5rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 2rem;
    justify-content: space-between;
}

/* The wordmark is live text in the page's own face rather than the logo file
   dropped in with <img>.
   The logo SVG sets its typeface with an @import inside the file, and an SVG
   loaded through <img> is not allowed to fetch anything -- so that route
   renders the wordmark in Helvetica while the headline beside it is in
   Schibsted Grotesk, which is worse than having no logo at all. The mark is
   inlined (it is two shapes) and takes its colour from the text around it, so
   it follows the light-mode override for free. ``assets/logo.svg`` remains
   the artwork of record for anyone who needs the lockup as one file. */
.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.72rem;
    color: var(--ink);
    text-decoration: none;
    font-weight: 500;
    font-size: 1.22rem;
    letter-spacing: -0.012em;
    white-space: nowrap;
}
.brand:hover { color: var(--ink); }
.brand .mark { width: 1.45em; height: 1.45em; flex: none; }

.nav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.6rem;
    font-size: 0.95rem;
}
.nav a {
    color: var(--ink-muted);
    text-decoration: none;
    padding: 0.15rem 0;
    border-bottom: 2px solid transparent;
}
.nav a:hover { color: var(--ink); }
.nav a[aria-current="page"] {
    color: var(--ink);
    border-bottom-color: var(--accent);
}

/* ---------------------------------------------------------------------------
 * Page scaffolding
 * ------------------------------------------------------------------------ */

main { display: block; }

.wrap {
    max-width: var(--page);
    margin: 0 auto;
    padding: 0 1.5rem;
}

.prose { max-width: var(--measure); }

section { padding: 3.6rem 0; }
section + section { border-top: 1px solid var(--rule); }

h1, h2, h3 {
    font-weight: 500;
    letter-spacing: -0.018em;
    line-height: 1.18;
    margin: 0 0 0.6rem;
}
h1 { font-size: clamp(2.1rem, 5vw, 3.1rem); }
h2 { font-size: clamp(1.45rem, 3vw, 1.95rem); margin-bottom: 0.9rem; }
h3 { font-size: 1.12rem; margin-bottom: 0.35rem; }

/* The one line a visitor is guaranteed to read.
 *
 * Set the way Jane Street and Citadel set theirs: three to eight words, all
 * caps, very large, tracking pulled in, lines nearly touching. Rule 11 of
 * docs/standards/MARKETING_AND_SCOPE.md. The
 * word count is the constraint that makes it work -- this size is unreadable
 * applied to a sentence, so if a hero line needs more than eight words the
 * line is wrong, not the type.
 *
 * `text-wrap: balance` keeps a three-line hero from ending on one orphaned
 * word; browsers without it just wrap normally. */
.display {
    font-size: clamp(2.3rem, 7.2vw, 4.6rem);
    line-height: 1.02;
    letter-spacing: -0.03em;
    text-transform: uppercase;
    font-weight: 500;
    text-wrap: balance;
    margin-bottom: 1.4rem;
}

p { margin: 0 0 1.15rem; }
p:last-child { margin-bottom: 0; }

.lede {
    font-size: clamp(1.1rem, 2.1vw, 1.3rem);
    line-height: 1.5;
    color: var(--ink);
    max-width: 44rem;
}

.eyebrow {
    font-family: var(--mono);
    font-size: 0.74rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent);
    margin: 0 0 0.9rem;
}

.muted { color: var(--ink-muted); }

/* A line worth stopping on. Used once per page at most -- the analogy on What
 * We Do is the whole of its current job, and rule 8 of the style guide is why
 * it appears once and is cashed out in literal terms immediately after. */
.pull {
    margin: 2.4rem 0;
    padding-left: 1.4rem;
    border-left: 2px solid var(--accent);
    font-size: clamp(1.25rem, 2.6vw, 1.6rem);
    line-height: 1.32;
    letter-spacing: -0.015em;
    max-width: 34rem;
}

/* The no-solicitation notice.
 *
 * A panel a reader cannot miss, not fine print. That is the whole point of
 * it: the firm is private, is not offering anything and cannot take an
 * individual's account, and the risk this guards against is a regulator
 * reading a public website as an invitation to the general public to invest.
 * A statement buried in 13px grey at the foot of the page is a weaker answer
 * to that than the same words set at reading size inside a bordered box.
 *
 * It repeats what the footer disclosure says. The repetition is deliberate.
 *
 * Accent border rather than a warning colour: this is a statement of how the
 * firm operates, not an error, and red would read as one.
 */
.notice {
    max-width: 48rem;
    padding: 1.6rem 1.7rem;
    border: 1px solid var(--accent);
    border-radius: 4px;
    background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.notice h2 {
    font-size: clamp(1.15rem, 2.3vw, 1.45rem);
    margin-bottom: 0.85rem;
}
.notice p {
    font-size: 0.95rem;
    line-height: 1.6;
    margin-bottom: 0.85rem;
}
.notice p:last-child { margin-bottom: 0; }

/* The closing band: one short line and the action, on a raised surface, so a
 * reader who scrolled to the end is not left at a dead stop. */
.band {
    background: var(--bg-raised);
    border-top: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
}
.band h2 { margin-bottom: 0.7rem; }

/* ---------------------------------------------------------------------------
 * Hero
 * ------------------------------------------------------------------------ */

.hero {
    padding: clamp(3.5rem, 9vw, 7rem) 0 clamp(3rem, 7vw, 5rem);
}

/* Weighted to the words, not to the picture.
 *
 * An even split gave the headline a ~390px column, and display type set
 * that narrow broke a six-word line over five lines. The headline is the
 * one thing a visitor is guaranteed to read, so it gets the room and the
 * mark takes what is left. */
.hero-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr);
    gap: clamp(2rem, 5vw, 3.5rem);
    align-items: center;
}

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

.hero h1 { margin-bottom: 1.1rem; }

.actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.7rem;
    margin-top: 1.9rem;
}

.btn {
    display: inline-block;
    padding: 0.62rem 1.25rem;
    border-radius: 3px;
    border: 1px solid var(--accent);
    color: var(--accent);
    text-decoration: none;
    font-size: 0.95rem;
}
.btn:hover { background: var(--accent); color: var(--accent-ink); }
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: transparent; color: var(--accent); }

/* ---------------------------------------------------------------------------
 * Figures
 * ------------------------------------------------------------------------ */

figure {
    margin: 2rem 0;
    max-width: 44rem;
}

figure img {
    display: block;
    width: 100%;
    height: auto;
}

figcaption {
    margin-top: 0.85rem;
    padding-top: 0.7rem;
    border-top: 1px solid var(--rule);
    font-size: 0.85rem;
    line-height: 1.55;
    color: var(--ink-muted);
}

/* Every figure on this site is drawn from closed-form curves, not from a
   build. The label is not decoration: under the SEC Marketing Rule a chart a
   reader could mistake for a measurement is a claim the firm has to be able
   to substantiate, and these would not survive that. See
   ``docs/marketing/web-SITE-NOTES.md`` §6. */
.tag {
    display: inline-block;
    font-family: var(--mono);
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-faint);
    border: 1px solid var(--rule);
    border-radius: 2px;
    padding: 0.05rem 0.42rem;
    margin-right: 0.45rem;
    vertical-align: 0.08em;
}

/* Inline SVG, drawn in the page's own colours.
 *
 * Classes rather than `fill="var(--ink)"` on the element. A presentation
 * attribute is not a style rule, and `var()` inside one is not substituted
 * everywhere -- Safari in particular drops it, which would leave the hero
 * mark and the sail illustration rendering in the SVG default of solid
 * black on a near-black page. A class is an ordinary CSS declaration and
 * cannot fail that way.
 *
 * Only the inline illustrations use these. The matplotlib figures are
 * separate documents loaded with <img> and cannot see this file at all,
 * which is why they ship as a dark file and a light one. */
.art { width: 100%; height: auto; display: block; }
.art .fill-none { fill: none; }
.art .s-rule { stroke: var(--rule); }
.art .s-ink { stroke: var(--ink); }
.art .s-faint { stroke: var(--ink-faint); }
.art .s-accent { stroke: var(--accent); }
.art .fill-accent-soft { fill: var(--accent); fill-opacity: 0.22; }
.art .t-muted { fill: var(--ink-muted); font-size: 13px; }

/* ---------------------------------------------------------------------------
 * Cards
 * ------------------------------------------------------------------------ */

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14.5rem, 1fr));
    gap: 1.4rem;
    margin-top: 2rem;
}

.card {
    background: var(--bg-raised);
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 1.4rem 1.35rem;
}
.card h3 { margin-bottom: 0.45rem; }
.card p { font-size: 0.95rem; color: var(--ink-muted); margin: 0; }
.card .icon { display: block; width: 2rem; height: 2rem; margin-bottom: 0.9rem; color: var(--accent); }

/* ---------------------------------------------------------------------------
 * "It is / it is not"
 *
 * Two lists rather than a <table>. The content is a set of paired statements,
 * not a grid of values that a reader will scan along a row, and at phone
 * width a seven-row two-column table either scrolls sideways or collapses to
 * fourteen unlabelled cells.
 * ------------------------------------------------------------------------ */

.contrast {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
    gap: 1.4rem;
    margin-top: 2rem;
}

.contrast > div {
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 1.3rem 1.4rem;
}
.contrast .is { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, transparent); }
.contrast .is-not { background: var(--bg-raised); }

.contrast h3 {
    font-family: var(--mono);
    font-size: 0.75rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    margin-bottom: 1rem;
}
.contrast .is h3 { color: var(--accent); }
.contrast .is-not h3 { color: var(--ink-faint); }

.contrast ul { margin: 0; padding: 0; list-style: none; }
.contrast li {
    padding: 0.55rem 0;
    font-size: 0.95rem;
    border-top: 1px solid var(--rule);
}
.contrast li:first-child { border-top: 0; padding-top: 0; }
.contrast .is-not li { color: var(--ink-muted); }

/* ---------------------------------------------------------------------------
 * Team
 * ------------------------------------------------------------------------ */

/* Person cards are a name and a title, so they are sized for that.
 *
 * The grid used to be `minmax(15rem, 1fr)`, which stretched two cards across
 * the full page width and left each one mostly empty — the layout was built
 * when the cards still carried a paragraph. Capped at 15rem and left-aligned
 * instead: the cards are the size of what is in them, and a third name would
 * sit beside them rather than changing the other two. */
.team {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 15rem));
    gap: 1rem;
    margin-top: 1.6rem;
    justify-content: start;
}

.person {
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 1.1rem 1.2rem;
}
.person .portrait {
    width: 2.6rem;
    height: 2.6rem;
    border-radius: 50%;
    background: var(--bg-raised);
    border: 1px solid var(--rule);
    display: grid;
    place-items: center;
    margin-bottom: 0.8rem;
    color: var(--ink-faint);
}
.person .role { font-family: var(--mono); font-size: 0.74rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); margin: 0; }
.person .role:not(:last-child) { margin-bottom: 0.6rem; }
.person p { font-size: 0.93rem; color: var(--ink-muted); margin: 0; }

/* A person card is a name and a title. No prose -- see
   docs/standards/MARKETING_AND_SCOPE.md §7, which is where the two
   rounds of paragraph bios that used to sit here went and why. `.person p`
   above is kept for the one line a card may eventually carry. */

/* ---------------------------------------------------------------------------
 * Definition rows, used for the contact block
 * ------------------------------------------------------------------------ */

.rows { margin-top: 1.6rem; border-top: 1px solid var(--rule); max-width: var(--measure); }
.rows > div {
    display: grid;
    grid-template-columns: minmax(10rem, 0.8fr) minmax(0, 1.6fr);
    gap: 0.4rem 1.5rem;
    padding: 0.85rem 0;
    border-bottom: 1px solid var(--rule);
}
.rows dt { color: var(--ink-muted); font-size: 0.93rem; }
.rows dd { margin: 0; }
/* A qualifier under an address, set smaller so it reads as a note on the
   line above rather than as a second line of contact detail. */
.rows dd .muted { display: inline-block; font-size: 0.85rem; line-height: 1.5; margin-top: 0.3rem; }
@media (max-width: 560px) {
    .rows > div { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------------
 * Footer
 * ------------------------------------------------------------------------ */

.footer {
    border-top: 1px solid var(--rule);
    background: var(--bg-sunken);
    padding: 2.6rem 0 3.2rem;
    margin-top: 1rem;
}

.footer-top {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem 2.5rem;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 1.6rem;
    border-bottom: 1px solid var(--rule);
}

.footer .brand { font-size: 1.02rem; color: var(--ink-muted); }
.footer .brand:hover { color: var(--ink); }

.footer-links { display: flex; flex-wrap: wrap; gap: 0.3rem 1.4rem; font-size: 0.9rem; }
.footer-links a { color: var(--ink-muted); text-decoration: none; }
.footer-links a:hover { color: var(--ink); }

/* The disclosure is identical on all four pages and is set at a size that is
   meant to be read. Shrinking it is how a site ends up with a disclosure it
   cannot point to. */
.disclosure {
    margin-top: 1.6rem;
    max-width: 52rem;
    font-size: 0.83rem;
    line-height: 1.6;
    color: var(--ink-faint);
}
.disclosure p { margin-bottom: 0.8rem; }

/* ---------------------------------------------------------------------------
 * Anything that is still a placeholder.
 *
 * Deliberately conspicuous. This is a first draft with open questions in
 * QUESTIONS.md, and a bracketed placeholder set in body text is exactly the
 * thing that survives to production.
 * ------------------------------------------------------------------------ */

.todo {
    background: color-mix(in srgb, var(--accent-2) 14%, transparent);
    border-bottom: 1px dotted var(--accent-2);
    padding: 0 0.22em;
    border-radius: 2px;
}

@media print {
    .nav, .actions { display: none; }
}
