/* ==========================================================================
   Myriad Nsamoo Inc — Design system
   Plain CSS. No build step. Runs exactly as uploaded.

   Palette derived by sampling assets/logo.png directly; every foreground and
   background pair below was measured against WCAG 2.1 and the ratio is noted
   inline. Layout treatment follows _reference/mocks/mock3.png: rules and
   columns, never cards with radii or drop shadows.

   CONTENTS
     01  Fonts
     02  Tokens — palette
     03  Tokens — type, spacing, layout
     04  Band contexts
     05  Reset
     06  Base elements
     07  Typography
     08  Layout primitives
     09  Rules and dividers
     10  Data tables
     11  Buttons and links
     12  Form fields
     13  Utilities
     14  Accessibility and motion
   ========================================================================== */


/* 01  FONTS ================================================================
   Self-hosted from assets/fonts/ — no third-party DNS or TLS round trip,
   which matters on high-latency mobile connections.

   Newsreader ships WITHOUT its optical-size axis: that cut it from 129 KB to
   56.7 KB. What opsz would have done is reproduced by hand in section 07 —
   negative tracking and weight 600 at display sizes, weight 700 and neutral
   tracking below ~24px, so hairlines stay solid on low-end screens.

   latin-ext is a separate face behind unicode-range, so it downloads only for
   readers who actually hit those characters (Scandinavia & EU coverage).

   Core latin budget: Newsreader roman 56.7 + italic 63.0 + Plex 44.6 = 164.4 KB.

   Add to the <head> of every page so the two roman faces start downloading
   before the CSS is parsed:
     <link rel="preload" href="assets/fonts/newsreader-latin.woff2"
           as="font" type="font/woff2" crossorigin>
     <link rel="preload" href="assets/fonts/ibmplexsans-latin.woff2"
           as="font" type="font/woff2" crossorigin>
   Do NOT preload the italic or latin-ext faces — they are conditional.
   ========================================================================== */

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/newsreader-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: 'Newsreader';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/newsreader-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: 'Newsreader';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/newsreader-italic-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: 'Newsreader';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/newsreader-italic-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: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../assets/fonts/ibmplexsans-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: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../assets/fonts/ibmplexsans-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;
}


/* 02  TOKENS — PALETTE =====================================================
   Raw values. Components never reference these directly; they use the
   semantic aliases in section 04, which remap per band.
   ========================================================================== */

:root {

  /* --- Dark bookend: header, hero, footer ------------------------------- */
  --ink-ground:    #040613;  /* page ground — sampled unmodified from the logo */
  --ink-card:      #0B1124;  /* panels, table bodies                          */
  --ink-panel:     #111931;  /* table headers, active tabs                    */
  --rule:          #1A2440;  /* hairline dividers                             */
  --rule-strong:   #26334F;  /* visible borders, input outlines               */

  /* Adjacent dark surfaces differ by only 1.08:1 — invisible on low-end
     screens. Layering is carried by the rules above, not by fill. */

  --text-hi:       #F2F5FA;  /* headlines            18.47:1  AAA */
  --text:          #C3CBD9;  /* body                 12.36:1  AAA */
  --text-mid:      #8E97A9;  /* secondary             5.92:1  AA  */
  --text-low:      #8089A0;  /* timestamps            4.97:1  AA  */

  --accent:        #2F6DC2;  /* logo blue — FILL ONLY on dark. As text it is
                                3.39:1 and fails. White on it as a fill is
                                5.14:1 and passes.                            */
  --accent-bright: #4A8BE0;  /* link + accent TEXT    5.02:1  AA  */
  --accent-tint:   #769ED1;  /* eyebrows, hover       6.28:1  AA
                                sampled from the logo tagline                 */
  --accent-dim:    #16294A;  /* chip and active-tab fill                      */

  --up:            #3FBF87;  /* gains                 7.47:1  AAA */
  --down:          #F0616A;  /* losses                5.49:1  AA  */
  --flat:          #8E97A9;  /* unchanged             5.92:1  AA  */
  --warn:          #D9A441;  /* delayed-quote notice  7.73:1  AAA */

  /* --- Light band: main content ----------------------------------------- */
  --paper:         #F7F9FC;  /* band ground — cool, carries the logo's cast   */
  --paper-raised:  #FFFFFF;  /* table rows, inset panels                      */
  --paper-sunken:  #EDF1F7;  /* table headers, alternating rows               */
  --rule-light:        #D3DCE8;  /* hairline dividers                         */
  --rule-light-strong: #C3CDDC;  /* column dividers, section rules            */

  --ink-hi:        #0A1020;  /* headlines            16.72:1  AAA */
  --ink:           #23304A;  /* body                 11.63:1  AAA */
  --ink-mid:       #4A5670;  /* secondary             6.49:1  AA  */
  --ink-low:       #626E88;  /* timestamps            4.51:1  AA  */

  --accent-ink:    #1F5AA8;  /* link text + fills on light  6.00:1  AA        */
  --accent-wash:   #E4ECF8;  /* chip fill on light                            */

  /* The dark-band data colours fail on paper — #3FBF87 is 2.21:1,
     #F0616A is 3.01:1, #D9A441 is 2.13:1. The light band needs its own. */
  --up-ink:        #157F52;  /* gains                 4.75:1  AA  */
  --down-ink:      #C42A32;  /* losses                5.35:1  AA  */
  --warn-ink:      #8A6410;  /* delayed-quote notice  5.09:1  AA  */

  /* Dark ground against paper is 19.13:1, so band edges read as hard
     architectural lines and need no border. */
}


/* 03  TOKENS — TYPE, SPACING, LAYOUT ======================================= */

:root {

  --serif: 'Newsreader', Georgia, 'Times New Roman', serif;
  --sans:  'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', Roboto,
           'Helvetica Neue', Arial, sans-serif;

  /* Fluid scale, 16 → 17px body. clamp() means no breakpoint juggling. */
  --fs-4xl:  clamp(2.625rem, 1.60rem + 5.10vw, 4.500rem);  /* 42 → 72  hero    */
  --fs-3xl:  clamp(2.250rem, 1.70rem + 2.70vw, 3.375rem);  /* 36 → 54  h1      */
  --fs-2xl:  clamp(1.875rem, 1.53rem + 1.70vw, 2.563rem);  /* 30 → 41  h2      */
  --fs-xl:   clamp(1.563rem, 1.36rem + 0.95vw, 1.938rem);  /* 25 → 31  h3      */
  --fs-lg:   clamp(1.313rem, 1.20rem + 0.55vw, 1.500rem);  /* 21 → 24  h4      */
  --fs-md:   clamp(1.125rem, 1.08rem + 0.22vw, 1.188rem);  /* 18 → 19  lead    */
  --fs-base: clamp(1.000rem, 0.97rem + 0.15vw, 1.063rem);  /* 16 → 17  body    */
  --fs-sm:   0.875rem;                                     /* 14  cells        */
  --fs-xs:   0.750rem;                                     /* 12  meta         */

  --lh-hero:  1.05;
  --lh-head:  1.18;
  --lh-body:  1.55;
  --lh-prose: 1.70;
  --lh-data:  1.35;

  --tracking-hero:  -0.025em;
  --tracking-head:  -0.015em;
  --tracking-wide:   0.14em;  /* the eyebrow — echoes the logo wordmark */

  /* Four-pixel base. */
  --space-1:  0.25rem;   /*   4 */
  --space-2:  0.5rem;    /*   8 */
  --space-3:  0.75rem;   /*  12 */
  --space-4:  1rem;      /*  16 */
  --space-5:  1.5rem;    /*  24 */
  --space-6:  2rem;      /*  32 */
  --space-7:  3rem;      /*  48 */
  --space-8:  4rem;      /*  64 */
  --space-9:  6rem;      /*  96 */
  --space-10: 8rem;      /* 128 */

  /* Section rhythm. This is a data terminal, not a print broadsheet: the
     previous 48–112px was leaving most of a screen empty between bands.
     Density is the point, so sections sit close and the hairline rules do
     the separating instead of whitespace. */
  --section-y:       clamp(1.75rem, 3vw, 2.75rem);   /* 28 → 44px */
  --section-y-loose: clamp(2.5rem, 4.5vw, 4rem);     /* 40 → 64px, editorial */
  --gutter:    clamp(1rem, 4vw, 2rem);
  --container:        1280px;
  --container-narrow:  760px;  /* editorial reading column */
  --measure:            68ch;
  --measure-narrow:     58ch;

  --hairline: 1px;
  --focus-width: 2px;
  --focus-offset: 2px;

  --masthead-h: 4.5rem;   /* 72px — also the anchor scroll offset */

  /* Fixed bands, not a theme switch. Declaring this stops mobile Chrome
     auto-darkening the light band and the form controls inside it. */
  color-scheme: light;
}


/* 04  BAND CONTEXTS ========================================================
   Components reference only the semantic aliases below, so a table, button or
   rule works unchanged in either band. Set the band on a wrapper element:
     <div class="band-dark"> … </div>
   The light band is the page default.
   ========================================================================== */

:root,
.band-light {
  --surface:        var(--paper);
  --surface-raised: var(--paper-raised);
  --surface-sunken: var(--paper-sunken);
  --hairline-color: var(--rule-light);
  --border-color:   var(--rule-light-strong);

  --fg-hi:  var(--ink-hi);
  --fg:     var(--ink);
  --fg-mid: var(--ink-mid);
  --fg-low: var(--ink-low);

  --link:        var(--accent-ink);
  --fill:        var(--accent-ink);
  --fill-fg:     #FFFFFF;          /* 6.80:1 on --accent-ink */
  --chip:        var(--accent-wash);
  --eyebrow-fg:  var(--accent-ink);

  --pos:  var(--up-ink);
  --neg:  var(--down-ink);
  --zero: var(--ink-mid);
  --caution: var(--warn-ink);
}

.band-dark {
  --surface:        var(--ink-ground);
  --surface-raised: var(--ink-card);
  --surface-sunken: var(--ink-panel);
  --hairline-color: var(--rule);
  --border-color:   var(--rule-strong);

  --fg-hi:  var(--text-hi);
  --fg:     var(--text);
  --fg-mid: var(--text-mid);
  --fg-low: var(--text-low);

  --link:        var(--accent-bright);  /* NOT --accent: it fails as text */
  --fill:        var(--accent);
  --fill-fg:     #FFFFFF;               /* 5.14:1 on --accent */
  --chip:        var(--accent-dim);
  --eyebrow-fg:  var(--accent-tint);

  --pos:  var(--up);
  --neg:  var(--down);
  --zero: var(--flat);
  --caution: var(--warn);
}

.band-dark,
.band-light {
  background-color: var(--surface);
  color: var(--fg);
}


/* 05  RESET ================================================================ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchored sections must clear the sticky masthead. */
  scroll-padding-top: calc(var(--masthead-h) + var(--space-4));
}

body {
  margin: 0;
  min-height: 100vh;
  background-color: var(--surface);
  color: var(--fg);
  font-family: var(--sans);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd { margin: 0; }

ul, ol { margin: 0; padding: 0; }

img, picture, video, canvas, svg, iframe {
  display: block;
  max-width: 100%;
}
img, video { height: auto; }

input, button, textarea, select { font: inherit; color: inherit; }

::selection {
  background: var(--accent);
  color: #FFFFFF;
}


/* 06  BASE ELEMENTS ======================================================== */

strong, b { font-weight: 600; }

small { font-size: var(--fs-sm); }

hr {
  border: 0;
  border-top: var(--hairline) solid var(--hairline-color);
  margin: var(--space-7) 0;
}

code, kbd, samp {
  font-family: ui-monospace, 'Cascadia Mono', 'Segoe UI Mono', Menlo, monospace;
  font-size: 0.9em;
}

abbr[title] { text-decoration: underline dotted; cursor: help; }


/* 07  TYPOGRAPHY ===========================================================
   Newsreader carries every heading; IBM Plex Sans carries body and data.
   Weight and tracking stand in for the optical-size axis that was dropped
   from the font file: heavier and looser as sizes fall.
   ========================================================================== */

h1, h2, h3, h4, h5, h6,
.h-hero {
  font-family: var(--serif);
  color: var(--fg-hi);
  text-wrap: balance;   /* progressive: ignored where unsupported */
}

.h-hero {
  font-size: var(--fs-4xl);
  font-weight: 600;
  line-height: var(--lh-hero);
  letter-spacing: var(--tracking-hero);
}

h1 {
  font-size: var(--fs-3xl);
  font-weight: 600;
  line-height: var(--lh-hero);
  letter-spacing: -0.02em;
}

h2 {
  font-size: var(--fs-2xl);
  font-weight: 600;
  line-height: var(--lh-head);
  letter-spacing: var(--tracking-head);
}

h3 {
  font-size: var(--fs-xl);
  font-weight: 600;
  line-height: var(--lh-head);
}

h4 {
  font-size: var(--fs-lg);
  font-weight: 700;   /* heavier: no opsz to thicken the hairlines for us */
  line-height: var(--lh-head);
}

h5, h6 {
  font-size: var(--fs-md);
  font-weight: 700;
  line-height: var(--lh-head);
}

/* The tracked-out uppercase that echoes the logo wordmark. This is the motif
   tying every page back to the mark — use it for section labels. */
.eyebrow {
  font-family: var(--sans);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--eyebrow-fg);
  margin: 0 0 var(--space-4);
}

.lead {
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  color: var(--fg);
  max-width: var(--measure-narrow);
}

/* Long-form passages — Our Spirit, Our Mission, Methodology, Coverage. */
.prose {
  max-width: var(--measure);
  line-height: var(--lh-prose);
}
.prose > * + * { margin-top: var(--space-5); }

/* A long uninterrupted read — the product.php message runs to eight
   paragraphs of heavily capitalised copy that must not be broken into cards
   or pull-quotes. The only tools left are measure and spacing, so the gap
   between paragraphs opens up and the column stays at the narrow measure
   rather than the full 68ch: long capitalised sentences are harder to track
   back from than sentence case, and a shorter line helps. */
.prose--message {
  max-width: var(--measure-narrow);
}
.prose--message > * + * { margin-top: var(--space-6); }
.prose h2, .prose h3, .prose h4 { margin-top: var(--space-8); }
.prose em, .prose cite { font-family: var(--serif); font-style: italic; }

/* Publication names and vessel titles sit in serif italic. */
cite, .pub {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.05em;   /* Newsreader runs small beside Plex */
}

blockquote.pullquote {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: var(--fs-xl);
  line-height: 1.35;
  color: var(--fg-hi);
  max-width: var(--measure-narrow);
  margin: var(--space-7) 0;
  padding-left: var(--space-5);
  border-left: 2px solid var(--fill);
}
blockquote.pullquote cite,
blockquote.pullquote .attrib {
  display: block;
  margin-top: var(--space-4);
  font-family: var(--sans);
  font-style: normal;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--fg-low);
}

.meta {
  font-size: var(--fs-xs);
  color: var(--fg-low);
  font-variant-numeric: tabular-nums;
}

.text-mid { color: var(--fg-mid); }
.text-low { color: var(--fg-low); }


/* 08  LAYOUT PRIMITIVES ==================================================== */

.wrap {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--narrow { max-width: var(--container-narrow); }

.section { padding-block: var(--section-y); }
.section--tight { padding-block: var(--space-5); }
.section--loose { padding-block: var(--section-y-loose); }

/* Section opener: a rule above the label, per mock3. */
.section-head {
  border-top: var(--hairline) solid var(--hairline-color);
  padding-top: var(--space-4);
  margin-bottom: var(--space-5);
}
.section-head > p:not(.eyebrow) {
  margin-top: var(--space-3);
  color: var(--fg-mid);
  max-width: var(--measure);
}

/* Columns divided by rules, never boxed into cards.

   Stacked is the mobile-first base. The divider then reads as ONE continuous
   vertical rule down the whole group: every item keeps its left border,
   including the first, and the separation between items is padding *inside*
   the bordered box — never margin or grid gap, either of which would break
   the rule into segments.

   Vertical rhythm has to stay right way up: the space between two items must
   clearly exceed the space between a heading and its own paragraph, or the
   group reads as one undifferentiated block. Adjacent items contribute
   --space-5 each, giving 48px between items against 12px inside one. */
.cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}

.col {
  min-width: 0;   /* lets long data strings shrink instead of blowing the grid */
  border-left: var(--hairline) solid var(--hairline-color);
  padding-left: var(--space-5);
  padding-block: var(--space-5);
}
.col:first-child { padding-top: 0; }
.col:last-child  { padding-bottom: 0; }

/* Default spacing inside an item, so the rhythm does not depend on a utility
   class being remembered in the markup. */
.col > * + * { margin-top: var(--space-3); }

/* Side by side. Each variant turns horizontal only at a width where all of
   its items fit on ONE row — so :first-child is reliably the only row start
   and the border reset below can never strip the rule off a wrapped item.
   This is why the column counts are explicit rather than auto-fit: auto-fit
   collapses silently, and CSS cannot then tell a stacked group from a
   horizontal one in order to scope the reset. */
@media (min-width: 640px) {
  .cols--2 { grid-template-columns: repeat(2, 1fr); }
  .cols--2 > .col { padding-block: 0; }
  .cols--2 > .col:first-child { border-left: 0; padding-left: 0; }
}

@media (min-width: 860px) {
  .cols--3 { grid-template-columns: repeat(3, 1fr); }
  .cols--3 > .col { padding-block: 0; }
  .cols--3 > .col:first-child { border-left: 0; padding-left: 0; }
}

@media (min-width: 1040px) {
  .cols--4 { grid-template-columns: repeat(4, 1fr); }
  .cols--4 > .col { padding-block: 0; }
  .cols--4 > .col:first-child { border-left: 0; padding-left: 0; }
}

/* Opts out of the rules entirely, for groups that want air instead of a
   divider. Safe to wrap, since there are no borders to misalign. */
.cols--gap {
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-6);
}
.cols--gap > .col {
  border-left: 0;
  padding-inline: 0;
  padding-block: 0;
}

/* A lattice for groups whose item count does not divide evenly into a row —
   the ten coverage regions, for instance. Every cell carries the same right
   and bottom hairline and the container supplies the top and left, so the
   grid stays a clean unbroken grid at any wrap point and any item count.
   This is the pattern to reach for instead of .cols whenever the number of
   items is not fixed, since .cols--N only guarantees correct borders when it
   holds exactly N items on a single row. */
.lattice {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0;
  border-top: var(--hairline) solid var(--hairline-color);
  border-left: var(--hairline) solid var(--hairline-color);
}

.lattice-cell {
  border-right: var(--hairline) solid var(--hairline-color);
  border-bottom: var(--hairline) solid var(--hairline-color);
  padding: var(--space-4) var(--space-5);
  min-width: 0;
}

.lattice-cell > h3,
.lattice-cell > h4 {
  font-size: var(--fs-md);
  font-weight: 700;
  line-height: var(--lh-head);
}

.lattice-cell > p {
  margin-top: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--fg-mid);
}

/* Closes a section with a rule and the link through to its full page. */
.section-foot {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: var(--hairline) solid var(--hairline-color);
}

.section-foot a {
  font-family: var(--sans);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  text-decoration: none;
  color: var(--link);
}
.section-foot a:hover { text-decoration: underline; }
.section-foot a::after {
  /* U+203A, not U+2192. The core latin subset carries U+2191 and U+2193 for
     the market tables but NOT the rightwards arrow, which would silently
     fall back to a system font and render at a different weight. Verified by
     measuring glyph widths against the loaded face. */
  content: ' \203A';
  text-decoration: none;
}

/* Stacked list separated by hairlines — news feeds, methodology, coverage. */
.stack { list-style: none; }
.stack > li {
  padding-block: var(--space-4);
  border-top: var(--hairline) solid var(--hairline-color);
}
.stack > li:first-child { border-top: 0; padding-top: 0; }
.stack > li:last-child { padding-bottom: 0; }


/* 09  RULES AND DIVIDERS ===================================================
   These carry the visual layering. Dark surfaces differ by only 1.08:1, so
   fill alone will not separate a panel from its ground.
   ========================================================================== */

.rule       { border-top: var(--hairline) solid var(--hairline-color); }
.rule-strong{ border-top: var(--hairline) solid var(--border-color); }

/* Short accent rule under a section label. */
.rule-accent {
  width: 48px;
  height: 2px;
  background: var(--fill);
  border: 0;
  margin: var(--space-4) 0 0;
}

.panel {
  background: var(--surface-raised);
  border: var(--hairline) solid var(--hairline-color);
  padding: var(--space-5);
  /* No radius, no shadow. Deliberate — see CLAUDE.md design direction. */
}


/* 10  DATA TABLES ==========================================================
   IBM Plex Sans has true tabular figures; columns stay aligned as values tick.
   ========================================================================== */

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.data-table caption {
  text-align: left;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--fg-low);
  padding-bottom: var(--space-3);
}

.data-table th {
  text-align: left;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-mid);
  padding: var(--space-3);
  border-bottom: var(--hairline) solid var(--border-color);
  white-space: nowrap;
}

.data-table td {
  padding: var(--space-3);
  font-size: var(--fs-sm);
  line-height: var(--lh-data);
  border-bottom: var(--hairline) solid var(--hairline-color);
}

.data-table tbody tr:last-child td { border-bottom: 0; }

.data-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Wide tables must scroll inside their own box, never the page body. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* A table at width:100% squashes instead of scrolling, which wraps
   instrument names down to one word per line in a narrow panel. Giving it a
   floor makes .table-scroll actually do its job. */
.table-scroll > .data-table { min-width: 400px; }

/* Gain and loss. Colour alone never carries the meaning — pair every value
   with the arrow glyph, which is already inside the core latin subset:
     <td class="num change-up">&#8593; 1.19%</td>
     <td class="num change-down">&#8595; 0.42%</td> */
.change-up   { color: var(--pos); font-weight: 600; }
.change-down { color: var(--neg); font-weight: 600; }
.change-flat { color: var(--zero); font-weight: 600; }

/* Required beneath every quote display. */
.quote-notice {
  font-size: var(--fs-xs);
  color: var(--caution);
  margin-top: var(--space-4);
}

/* TradingView attribution must stay visible — do not hide this. */
.tv-attribution {
  font-size: var(--fs-xs);
  color: var(--fg-low);
}
.tv-attribution a { color: var(--link); }


/* 11  BUTTONS AND LINKS ====================================================
   The accent split: --fill is the logo blue used as a background with white
   on it. --link is a different, lighter blue for text. The logo blue is never
   a text colour on the dark band, where it measures 3.39:1.
   ========================================================================== */

a {
  color: var(--link);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
a:hover { text-decoration-thickness: 2px; }

/* Editorial link: underline replaced by a rule that thickens on hover. */
.link {
  text-decoration: none;
  border-bottom: var(--hairline) solid var(--border-color);
  transition: border-color 120ms ease;
}
.link:hover { border-bottom-color: var(--link); }

.btn {
  display: inline-block;
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.2;
  padding: var(--space-3) var(--space-5);
  border: var(--hairline) solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.btn--fill {
  background: var(--fill);
  color: var(--fill-fg);
}
.btn--fill:hover { background: var(--accent-bright); }
.band-light .btn--fill:hover { background: var(--accent); }

.btn--ghost {
  background: transparent;
  border-color: var(--border-color);
  color: var(--fg-hi);
}
.btn--ghost:hover { border-color: var(--link); }

.chip {
  display: inline-block;
  background: var(--chip);
  color: var(--fg);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: var(--space-1) var(--space-3);
}


/* 12  FORM FIELDS ========================================================== */

.field { display: block; margin-bottom: var(--space-5); }

.field > label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-mid);
  margin-bottom: var(--space-2);
}

.field input,
.field textarea,
.field select {
  width: 100%;
  background: var(--surface-raised);
  color: var(--fg-hi);
  border: var(--hairline) solid var(--border-color);
  padding: var(--space-3);
  font-size: var(--fs-base);
}
.band-dark .field input,
.band-dark .field textarea,
.band-dark .field select {
  background: var(--surface-sunken);
}

.field textarea { min-height: 8rem; resize: vertical; }

.field input::placeholder,
.field textarea::placeholder { color: var(--fg-low); opacity: 1; }

.field input:hover,
.field textarea:hover { border-color: var(--link); }

/* Server-side validation messages from php/contact.php. */
.field-error {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--neg);
}
.field input[aria-invalid='true'],
.field textarea[aria-invalid='true'] { border-color: var(--neg); }

.form-note { font-size: var(--fs-xs); color: var(--fg-low); }

.field select {
  /* Match the inputs; the UA select is not styled by the input rules. */
  appearance: none;
  background-image: none;
  border-radius: 0;
}

/* Submission outcome. A rule down the left rather than a tinted card, so it
   sits with the rest of the system. */
.form-status {
  margin-block: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-left: 2px solid var(--border-color);
  background: var(--surface-sunken);
  font-size: var(--fs-sm);
  color: var(--fg);
}
.form-status--ok {
  border-left-color: var(--pos);
  color: var(--fg-hi);
}
.form-status--error {
  border-left-color: var(--neg);
  color: var(--fg-hi);
}

/* The honeypot. Hidden from people without display:none, which some
   automated submitters check for before deciding to fill a field. Kept out
   of the tab order and off the accessibility tree by the markup. */
.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}


/* 13  UTILITIES ============================================================ */

.measure        { max-width: var(--measure); }
.measure-narrow { max-width: var(--measure-narrow); }
.tabular        { font-variant-numeric: tabular-nums; }
.nowrap         { white-space: nowrap; }
.center         { margin-inline: auto; }

.mt-0 { margin-top: 0; }
.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mt-5 { margin-top: var(--space-5); }
.mt-6 { margin-top: var(--space-6); }
.mt-7 { margin-top: var(--space-7); }

/* Visible to screen readers only. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Reserve widget height before it initialises so lazy-loaded TradingView
   embeds do not shift the page as they arrive. Set --h per placement. */
.widget-slot {
  min-height: var(--h, 300px);
  display: block;
  position: relative;
}

/* Sits in the reserved space until the widget mounts, and is replaced by the
   fallback line if the third-party script fails to load. Both are plain text
   rather than a spinner: on a slow connection an animated placeholder costs
   paint work at exactly the moment the page can least afford it. */
.widget-placeholder,
.widget-fallback {
  margin: 0;
  padding-block: var(--space-4);
}
.widget-fallback a { color: var(--link); }


/* 14  ACCESSIBILITY AND MOTION ============================================= */

/* Never remove the focus ring. Both band values were measured: --accent-ink
   is 6.00:1 on paper, --accent-bright is 5.02:1 on the dark panel. */
:focus-visible {
  outline: var(--focus-width) solid var(--link);
  outline-offset: var(--focus-offset);
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -4rem;
  z-index: 100;
  background: var(--accent);
  color: #FFFFFF;
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: var(--space-3) var(--space-4);
  transition: top 120ms ease;
}
.skip-link:focus { top: var(--space-4); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .band-dark, .band-light {
    background: #FFFFFF !important;
    color: #000000 !important;
  }
  .widget-slot, .skip-link { display: none; }
  a[href^='http']::after {
    content: ' (' attr(href) ')';
    font-size: 0.8em;
    word-break: break-all;
  }
}


/* 15  MASTHEAD =============================================================
   Dark bookend. The brand lockup is assets/logo-mark.png — the M|N monogram
   cropped from assets/logo.png — beside the wordmark set as live text.

   The wordmark is NOT the image: in the source file it is 23px tall in a
   418px image, so at masthead scale it would render around 4px and be
   unreadable. Setting it in tracked-out IBM Plex Sans reproduces what the
   logo does (a widely-tracked sans wordmark), stays legible at every size,
   costs no bytes, and is selectable and readable by screen readers.

   The monogram crop's background is flat #040613, identical to --ink-ground,
   so the image edge is invisible against the bar.
   ========================================================================== */

.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--ink-ground);
  border-bottom: var(--hairline) solid var(--rule);
}

.masthead-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  min-height: var(--masthead-h);
  position: relative;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  flex-shrink: 0;
}
.brand img {
  height: 2.5rem;          /* 40px; intrinsic 287x180 keeps it sharp at 2x */
  width: auto;
}
.brand-name {
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--text-hi);
  white-space: nowrap;
}

/* --- Navigation ---------------------------------------------------------- */

.nav-list {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  list-style: none;
}

.nav-link {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-mid);
  text-decoration: none;
  padding-block: var(--space-2);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  transition: color 120ms ease, border-color 120ms ease;
}
.nav-link:hover { color: var(--text-hi); }

/* CLAUDE.md: Team and Interactive Content must be prominent.

   Prominence must NOT borrow the current-page treatment. These previously
   sat at --text-hi, the same brightness as the active item, so two entries
   read as active at once. Three distinct tiers instead:
     default  --text-mid   the rest of the bar
     feature  --text       brighter, but plainly not the active item
     current  --text-hi    brightest, and the only one with an underline */
.nav-link--feature { color: var(--text); }

/* Higher specificity than .nav-link--feature, so a feature item that is
   also the current page still resolves to the current-page treatment. */
.nav-link[aria-current='page'] {
  color: var(--text-hi);
  border-bottom-color: var(--accent);
}

/* --- Mobile menu --------------------------------------------------------- */

.nav-toggle {
  display: none;
  align-items: center;
  gap: var(--space-2);
  background: transparent;
  border: var(--hairline) solid var(--rule-strong);
  color: var(--text-hi);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  min-height: 44px;        /* touch target */
}
.nav-toggle:hover { border-color: var(--accent-bright); }

.nav-toggle-bars {
  position: relative;
  display: block;
  width: 16px;
  height: 2px;
  background: currentColor;
}
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: '';
  position: absolute;
  left: 0;
  width: 16px;
  height: 2px;
  background: currentColor;
  transition: transform 140ms ease, top 140ms ease;
}
.nav-toggle-bars::before { top: -5px; }
.nav-toggle-bars::after  { top: 5px; }

.nav-toggle[aria-expanded='true'] .nav-toggle-bars { background: transparent; }
.nav-toggle[aria-expanded='true'] .nav-toggle-bars::before { top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded='true'] .nav-toggle-bars::after  { top: 0; transform: rotate(-45deg); }

/* Eight items, several of them long, need a generous collapse point. */
@media (max-width: 1080px) {
  .nav-toggle { display: inline-flex; }

  .nav-panel {
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    background: var(--ink-ground);
    border-top: var(--hairline) solid var(--rule);
    border-bottom: var(--hairline) solid var(--rule);
    padding-bottom: var(--space-4);
    max-height: calc(100vh - var(--masthead-h));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* The panel carries the hidden attribute in the markup so the collapsed
     menu never paints open before the script runs. An inline script in each
     <head> sets .has-js before first paint.

     With scripting off .has-js is never set, so the rule below restores the
     panel as a plain static block and the site stays fully navigable. */
  .nav-panel[hidden] { display: none; }

  html:not(.has-js) .nav-panel[hidden] {
    display: block;
    position: static;
    max-height: none;
  }
  html:not(.has-js) .nav-toggle { display: none; }

  .nav-list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding-inline: var(--gutter);
  }
  .nav-item { border-top: var(--hairline) solid var(--rule); }
  .nav-item:first-child { border-top: 0; }

  .nav-link {
    padding-block: var(--space-4);
    font-size: var(--fs-sm);
    letter-spacing: 0.08em;
    border-bottom: 0;
    border-left: 2px solid transparent;
    padding-left: var(--space-3);
    margin-left: calc(var(--space-3) * -1);
  }
  .nav-link[aria-current='page'] {
    border-bottom-color: transparent;
    border-left-color: var(--accent);
  }
}

/* Above the collapse point the panel is always shown, even if the hidden
   attribute is still set from a narrower viewport. */
@media (min-width: 1081px) {
  .nav-panel[hidden] { display: block; }
}

@media (max-width: 420px) {
  .brand img { height: 2.125rem; }
  .brand-name { font-size: 0.8125rem; letter-spacing: 0.14em; }
  .nav-toggle { padding-inline: var(--space-3); }
  .nav-toggle-label { display: none; }
}


/* 16  SITE FOOTER ==========================================================
   The other dark bookend. Columns divided by rules, per mock3.

   Two standing requirements from CLAUDE.md are enforced in the markup: the
   copyright year is rendered by PHP with date('Y') — never hardcoded, and no
   longer dependent on JavaScript — and no @mn email address appears anywhere.
   ========================================================================== */

.site-footer {
  background: var(--ink-ground);
  border-top: var(--hairline) solid var(--rule);
  padding-top: var(--space-8);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 0;
}
@media (max-width: 900px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .footer-grid { grid-template-columns: 1fr; }
}

.footer-col {
  padding-inline: var(--space-6);
  border-left: var(--hairline) solid var(--rule);
  min-width: 0;
}
.footer-col:first-child { padding-left: 0; border-left: 0; }

@media (max-width: 900px) {
  .footer-col {
    padding-inline: 0;
    border-left: 0;
    border-top: var(--hairline) solid var(--rule);
    padding-block: var(--space-5);
  }
  .footer-col:first-child { border-top: 0; padding-top: 0; }
}

.footer-heading {
  font-family: var(--sans);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-low);
  margin-bottom: var(--space-4);
}

.footer-links { list-style: none; }
.footer-links li + li { margin-top: var(--space-3); }
.footer-links a {
  font-size: var(--fs-sm);
  color: var(--text-mid);
  text-decoration: none;
}
.footer-links a:hover { color: var(--text-hi); }

.footer-address {
  font-style: normal;
  font-size: var(--fs-sm);
  color: var(--text-mid);
  line-height: var(--lh-body);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: var(--space-8);
  padding-block: var(--space-5);
  border-top: var(--hairline) solid var(--rule);
  font-size: var(--fs-xs);
  color: var(--text-low);
}


/* 17  HERO =================================================================
   Sits inside the dark bookend, directly beneath the masthead.
   ========================================================================== */

/* Full-bleed image behind the headline. The band element carries the photo;
   an overlay pseudo-element sits between photo and text.

   The overlay is not decoration — it is what keeps the headline legible over
   an image whose brightness we do not control. It runs from nearly opaque at
   the left, where the text sits, to light at the right, so the picture still
   reads. Measured over the placeholder, --text-hi holds well past AA at the
   headline's position; a brighter final photo will need the left stop raised
   rather than the text darkened. */
.hero-band {
  position: relative;
  background-color: var(--ink-ground);
  background-image: url('../images/hero.jpg');
  background-size: cover;
  background-position: center right;
  background-repeat: no-repeat;
  isolation: isolate;
}

.hero-band::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    linear-gradient(
      100deg,
      rgba(4, 6, 19, 0.97) 0%,
      rgba(4, 6, 19, 0.92) 34%,
      rgba(4, 6, 19, 0.70) 62%,
      rgba(4, 6, 19, 0.52) 100%
    );
}

/* Keeps the join with the ticker strip from looking like a seam. */
.hero-band::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 96px;
  z-index: 0;
  background: linear-gradient(to bottom, rgba(4, 6, 19, 0), var(--ink-ground));
}

.hero-band > * { position: relative; z-index: 1; }

.hero { padding-block: clamp(2.5rem, 6vw, 5rem); }

.hero h1 { max-width: 16ch; }

.hero .lead {
  margin-top: var(--space-4);
  color: var(--text);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

@media (max-width: 700px) {
  /* Narrow screens crop the picture to almost nothing useful and the text
     needs the full width, so flatten the gradient to a near-solid ground. */
  .hero-band::before {
    background: linear-gradient(
      100deg,
      rgba(4, 6, 19, 0.97) 0%,
      rgba(4, 6, 19, 0.93) 70%,
      rgba(4, 6, 19, 0.88) 100%
    );
  }
}


/* 17b  MARKET TILE STRIP ===================================================
   The scrolling strip from mock3: one Mini Symbol Overview tile per symbol,
   each carrying name, price, change and a sparkline. Sits in the dark
   bookend directly beneath the Ticker Tape.

   Division of labour: the tape carries all thirty symbols cheaply as text,
   the strip carries the charts. Thirty simultaneous iframes would breach
   the performance rules, so js/widgets.js mounts only the tiles near the
   viewport and destroys them once they scroll well clear — never more than
   eight alive at once. Everything here is sized so a tile occupies exactly
   the same box whether it is live or not, and the strip never reflows as
   tiles come and go.

   No autoplay. It scrolls by touch, drag, wheel or keyboard only, so a
   reader on a slow connection never pays for tiles they do not look at.
   ========================================================================== */

.strip-wrap {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  gap: 0;
  border-top: var(--hairline) solid var(--rule);
}

@media (max-width: 720px) {
  .strip-wrap { grid-template-columns: 1fr; }
}

.strip-label {
  padding: var(--space-4) var(--space-4) var(--space-4) 0;
  border-right: var(--hairline) solid var(--rule);
  min-width: 0;
}
@media (max-width: 720px) {
  .strip-label {
    border-right: 0;
    border-bottom: var(--hairline) solid var(--rule);
    padding-right: 0;
  }
}
.strip-label .eyebrow { margin-bottom: var(--space-2); }
.strip-label .quote-notice { margin-top: 0; }
.strip-label a {
  display: inline-block;
  margin-top: var(--space-3);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--link);
  text-decoration: none;
}
.strip-label a:hover { text-decoration: underline; }
.strip-label a::after { content: ' \203A'; }

.tile-strip {
  display: flex;
  gap: 0;
  overflow-x: auto;
  overflow-y: hidden;
  /* pan-x keeps native horizontal scrolling on touch while leaving vertical
     page scrolling to the page. */
  touch-action: pan-x;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  cursor: grab;
  scrollbar-width: thin;
  scrollbar-color: var(--rule-strong) transparent;
}
.tile-strip.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none;
  /* Suppress the click that ends a drag. */
  user-select: none;
}
.tile-strip:focus-visible {
  outline: var(--focus-width) solid var(--accent-bright);
  outline-offset: -2px;
}

.tile-strip::-webkit-scrollbar { height: 6px; }
.tile-strip::-webkit-scrollbar-track { background: transparent; }
.tile-strip::-webkit-scrollbar-thumb { background: var(--rule-strong); }

.tile {
  flex: 0 0 var(--tile-w, 180px);
  width: var(--tile-w, 180px);
  height: var(--tile-h, 180px);
  border-left: var(--hairline) solid var(--rule);
  scroll-snap-align: start;
  position: relative;
  overflow: hidden;
}
.tile:first-child { border-left: 0; }

/* Shown before a tile mounts and again after it is destroyed, so a scrolled
   -away tile still reads as a labelled slot rather than a hole. */
.tile-ph {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding: var(--space-3);
  pointer-events: none;
}

/* display:flex above beats the user-agent rule for the hidden attribute, so
   without this the placeholder shows straight through a live tile — the
   widget is transparent. Scoped rather than a global [hidden] override,
   because .nav-panel deliberately overrides hidden at desktop widths. */
.tile-ph[hidden] { display: none; }
.tile-name {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-mid);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tile-sym {
  font-size: 0.6875rem;
  color: var(--text-low);
  font-variant-numeric: tabular-nums;
}

.tile .tradingview-widget-container {
  position: relative;
  z-index: 1;
  height: var(--tile-h, 180px);
}

@media (max-width: 480px) {
  .tile-strip { --tile-w: 158px; }
}


/* 17c  INTERIOR PAGE HEADER ================================================
   The dark bookend at the top of every page that is not the homepage.
   Shorter than the homepage hero and with no image behind it.
   ========================================================================== */

.page-head { padding-block: clamp(2rem, 4.5vw, 3.5rem); }
.page-head h1 { max-width: 20ch; }
.page-head .lead { margin-top: var(--space-4); color: var(--text); }

/* Anchor links to the distinct sections of a two-part page. CLAUDE.md
   requires each section to keep its own heading and its own anchor, so
   these are real in-page links, not a tab strip. */
.section-jump {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: var(--hairline) solid var(--rule);
}
.section-jump a {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--accent-tint);
  text-decoration: none;
}
.section-jump a:hover { color: var(--text-hi); }
.section-jump a::after { content: ' \203A'; }

/* Numbered editorial list. Used for Our Methodology, so it reads as a
   different kind of thing from the coverage lattice on the same page. */
.numbered {
  list-style: none;
  counter-reset: step;
  border-top: var(--hairline) solid var(--hairline-color);
}
.numbered > li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr);
  gap: var(--space-4);
  padding-block: var(--space-4);
  border-bottom: var(--hairline) solid var(--hairline-color);
}
.numbered > li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--sans);
  font-size: var(--fs-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  color: var(--link);
  padding-top: 0.15em;
}
.numbered h3 {
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: var(--lh-head);
}
.numbered p {
  margin-top: var(--space-2);
  color: var(--fg-mid);
  max-width: var(--measure);
}
@media (max-width: 560px) {
  .numbered > li { grid-template-columns: 2.25rem minmax(0, 1fr); gap: var(--space-3); }
}


/* 17d  MEDIA PLAYERS =======================================================
   Self-hosted video and audio, played by the browser's own controls. No
   third-party player, so nothing loads from another origin and no tracking
   script rides along with a view.

   Every player carries preload="none" and a poster, so a visit costs one
   small JPEG rather than a video file. That is the whole point on a
   connection that is slow or metered: the media downloads when someone
   asks for it and not before.
   ========================================================================== */

.player {
  display: block;
  width: 100%;
  height: auto;
  /* Holds the box before any media loads, so the poster swapping in causes
     no layout shift. */
  aspect-ratio: 16 / 9;
  background: var(--ink-ground);
  border: var(--hairline) solid var(--border-color);
  /* A video is replaced content and will happily overflow a narrow screen
     without this. */
  max-width: 100%;
}

.player-caption {
  margin-top: var(--space-3);
  font-size: var(--fs-sm);
  color: var(--fg-mid);
  max-width: var(--measure);
}

.player-meta {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--fs-xs);
  color: var(--fg-low);
  font-variant-numeric: tabular-nums;
}

/* Fallback shown only when the browser can play no supplied source. */
.player-fallback {
  font-size: var(--fs-sm);
  color: var(--fg-mid);
  padding: var(--space-4);
}

/* --- Video grid ---------------------------------------------------------- */

.video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 0;
  border-top: var(--hairline) solid var(--hairline-color);
  border-left: var(--hairline) solid var(--hairline-color);
}

.video-cell {
  border-right: var(--hairline) solid var(--hairline-color);
  border-bottom: var(--hairline) solid var(--hairline-color);
  padding: var(--space-4);
  min-width: 0;
}

.video-cell h3 {
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: var(--lh-head);
  margin-top: var(--space-3);
}

@media (max-width: 420px) {
  /* One per row on a phone; a 300px minimum would otherwise force a
     horizontal scroll on the narrowest handsets. */
  .video-grid { grid-template-columns: 1fr; }
  .video-cell { padding: var(--space-3); }
}

/* --- Audio --------------------------------------------------------------- */

.audio-list { list-style: none; }

.audio-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: var(--space-5);
  align-items: center;
  padding-block: var(--space-5);
  border-top: var(--hairline) solid var(--hairline-color);
}
.audio-item:first-child { border-top: 0; padding-top: 0; }

@media (max-width: 720px) {
  .audio-item {
    grid-template-columns: 1fr;
    gap: var(--space-3);
    align-items: start;
  }
}

.audio-player {
  width: 100%;
  max-width: 100%;
  /* The native audio element has its own intrinsic height; do not impose an
     aspect ratio on it the way .player does for video. */
  height: 40px;
}


/* 17e  TEAM CARDS ==========================================================
   Follows the blueprint in _reference/ (A849647B…png): a coloured rule
   across the top of each card, the name, the role in the accent colour,
   then dashed bullets.

   Two departures from that blueprint, both deliberate:

     - It is drawn in the old site's cream-and-tan palette. CLAUDE.md says
       the palette derives from assets/logo.png and that the mocks' accent
       colours are not authoritative, so the rule and role take our blue.
     - It shows the superseded four-person roster. The names here come from
       CLAUDE.md, which the client confirmed on 11 September 2026.

   Still rules-and-columns: the top rule and hairline borders do the work,
   with no radius and no shadow.
   ========================================================================== */

.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-5);
}

.team-card {
  display: flex;
  flex-direction: column;
  border: var(--hairline) solid var(--hairline-color);
  /* The coloured rule the blueprint puts across the top of every card. */
  border-top: 3px solid var(--fill);
  background: var(--surface-raised);
  padding: 0 0 var(--space-4);
  min-width: 0;
}

/* The four supplied headshots have quite different shapes — 800x631,
   800x800, 800x960 and 800x1182 — so a uniform 4:5 card crops each of them
   differently: up to 37% off the sides of the widest, and 15% off the top
   and bottom of the tallest.

   object-position pulls the crop window upward. Centred, the tall portrait
   loses ~91px off the top, which clips the crown of the head; biasing to
   25% keeps every face whole. Horizontal stays centred, which suits all
   four since each subject is centred in frame.

   If a future headshot is composed off-centre, give that one image its own
   object-position rather than changing this default. */
.team-photo {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 25%;
  background: var(--ink-card);
  border-bottom: var(--hairline) solid var(--hairline-color);
}

.team-body { padding: var(--space-4) var(--space-4) 0; }

.team-name {
  font-family: var(--serif);
  font-size: var(--fs-lg);
  font-weight: 700;
  line-height: var(--lh-head);
  color: var(--fg-hi);
}

.team-role {
  margin-top: var(--space-2);
  font-family: var(--sans);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0.04em;
  color: var(--link);
}

/* Blandina Jabbari's sub-line. Italic serif at body weight, so it reads as
   an aside to the role above rather than a second job title — the role is
   upright tracked sans in the accent colour, this is neither. */
.team-subrole {
  margin-top: var(--space-2);
  font-family: var(--serif);
  font-style: italic;
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.4;
  color: var(--fg-mid);
}

/* Dashed bullets, as the blueprint draws them: an em dash in the accent
   colour rather than a disc. */
.team-facts {
  list-style: none;
  margin-top: var(--space-4);
}
.team-facts > li {
  position: relative;
  padding-left: var(--space-5);
  font-size: var(--fs-sm);
  line-height: 1.45;
  color: var(--fg-mid);
}
.team-facts > li + li { margin-top: var(--space-3); }
.team-facts > li::before {
  content: '\2014';          /* em dash, inside the core latin subset */
  position: absolute;
  left: 0;
  color: var(--link);
}

/* The closing line beneath the cards. */
.team-strengths {
  margin-top: var(--space-7);
  padding-top: var(--space-5);
  border-top: var(--hairline) solid var(--hairline-color);
  font-size: var(--fs-sm);
  color: var(--fg-mid);
  max-width: var(--measure);
}
.team-strengths b {
  color: var(--link);
  font-weight: 600;
}


/* 18  DATA BAND ============================================================
   The dense three-column band from mock3: Latest News | Markets Overview |
   Economic Indicators, side by side and divided by rules.
   ========================================================================== */

.data-band {
  display: grid;
  grid-template-columns: 0.95fr 1.5fr 1fr;
  gap: 0;
  border-top: var(--hairline) solid var(--hairline-color);
  border-bottom: var(--hairline) solid var(--hairline-color);
}

@media (max-width: 1100px) {
  .data-band { grid-template-columns: 1fr 1fr; }
  /* The third panel spans both columns rather than leaving a hole. */
  .data-panel:nth-child(3) { grid-column: 1 / -1; }
}
@media (max-width: 720px) {
  .data-band { grid-template-columns: 1fr; }
  .data-panel:nth-child(3) { grid-column: auto; }
}

.data-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: var(--space-4) var(--space-5);
  border-left: var(--hairline) solid var(--hairline-color);
}
.data-panel:first-child { border-left: 0; }

@media (max-width: 1100px) {
  .data-panel:nth-child(3) {
    border-left: 0;
    border-top: var(--hairline) solid var(--hairline-color);
  }
}
@media (max-width: 720px) {
  .data-panel { border-left: 0; border-top: var(--hairline) solid var(--hairline-color); }
  .data-panel:first-child { border-top: 0; }
}

/* Panel header: label left, source attribution right, rule beneath. */
.data-panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-3);
  border-bottom: var(--hairline) solid var(--hairline-color);
}

.data-panel-head h2,
.data-panel-head h3 {
  font-family: var(--sans);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--fg-hi);
  margin: 0;
}

.data-panel-source {
  font-size: var(--fs-xs);
  color: var(--fg-low);
  white-space: nowrap;
}
.data-panel-source a { color: var(--link); }

/* Pushes the panel's link-through to the bottom so all three align. */
.data-panel-foot {
  margin-top: auto;
  padding-top: var(--space-3);
  border-top: var(--hairline) solid var(--hairline-color);
}
.data-panel-foot a {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-decoration: none;
  color: var(--link);
}
.data-panel-foot a:hover { text-decoration: underline; }
.data-panel-foot a::after { content: ' \203A'; }

/* --- Tabs ---------------------------------------------------------------- */

/* The row scrolls rather than pushing the page wider.

   Without this, markets.php scrolled sideways at every phone width: its
   second tablist holds five tabs whose content is ~398px, and in a 328px
   box with overflow visible that forced the whole document to 414px. The
   tabs cannot wrap — they are a single row by definition — so the row has
   to scroll, exactly as .table-scroll does for wide tables. */
.tabs {
  display: flex;
  gap: var(--space-4);
  margin-bottom: var(--space-3);
  border-bottom: var(--hairline) solid var(--hairline-color);
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  /* Keeps a sideways flick inside the tab row instead of it turning into a
     back-navigation gesture. */
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border-color) transparent;
}

.tabs::-webkit-scrollbar { height: 4px; }
.tabs::-webkit-scrollbar-track { background: transparent; }
.tabs::-webkit-scrollbar-thumb { background: var(--border-color); }

.tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 0 0 var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--fg-mid);
  cursor: pointer;
  white-space: nowrap;
  /* A flex item shrinks by default. Left to do that the labels would be
     squeezed instead of the row scrolling, which is the opposite of what
     the overflow above is for. */
  flex: 0 0 auto;
}
.tab:hover { color: var(--fg-hi); }
.tab[aria-selected='true'] {
  color: var(--fg-hi);
  border-bottom-color: var(--fill);
}

/* The chart sits directly above its quote list inside a tab panel, separated
   by a rule rather than a gap. */
.chart-slot {
  border-bottom: var(--hairline) solid var(--hairline-color);
  margin-bottom: var(--space-3);
  padding-bottom: var(--space-2);
}

/* --- Economic indicator rows --------------------------------------------- */

.indicators { list-style: none; }

.indicator {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-3);
  border-top: var(--hairline) solid var(--hairline-color);
}
.indicator:first-child { border-top: 0; }

.indicator-name {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--fg-hi);
  min-width: 0;
}
.indicator-period {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--fg-low);
  margin-top: 1px;
}

.indicator-value {
  font-size: var(--fs-md);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--fg-hi);
  white-space: nowrap;
}
/* --- Symbol picker -------------------------------------------------------
   The clickable quote list that drives the Symbol Overview chart.

   This list is ours rather than TradingView's, and it has to be. Their
   Market Overview rows live inside a cross-origin iframe: they emit no
   postMessage on click, and with largeChartUrl set they become plain
   anchors carrying target="_blank", which no config option changes. A row
   there can only ever open a new tab — it can never retarget a chart on
   the page it sits on. Verified directly against the rendered widget.

   Live prices for the selected symbol come from the chart's own header,
   and the full multi-symbol price tables are the All Securities section
   further down the page. */

.symbol-picker {
  list-style: none;
  border-top: var(--hairline) solid var(--hairline-color);
}

.symbol-picker > li { border-bottom: var(--hairline) solid var(--hairline-color); }

.symbol-picker button {
  display: flex;
  width: 100%;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  background: none;
  border: 0;
  border-left: 2px solid transparent;
  padding: var(--space-3) var(--space-4);
  text-align: left;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.symbol-picker button:hover { background: var(--surface-sunken); }

.symbol-picker button[aria-pressed='true'] {
  background: var(--surface-sunken);
  border-left-color: var(--fill);
}

.sp-sym {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--fg-hi);
  font-variant-numeric: tabular-nums;
}
.sp-name {
  font-size: var(--fs-xs);
  color: var(--fg-low);
  text-align: right;
}

/* --- Article feed lists --------------------------------------------------
   Headlines only, each linking out to its source. No article text is ever
   reproduced here — see the data-source rules in CLAUDE.md. */

.feed-list { list-style: none; }

.feed-item a {
  display: block;
  font-size: var(--fs-sm);
  line-height: 1.4;
  color: var(--fg-hi);
  text-decoration: none;
}
.feed-item a:hover { color: var(--link); text-decoration: underline; }

.feed-meta {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--fs-xs);
  color: var(--fg-low);
}

/* --- Awaiting-data state -------------------------------------------------
   Used where a panel's live source is not wired up yet. It must never be
   mistaken for a real value, so it shows an em dash rather than a number. */
.awaiting { color: var(--fg-low); font-variant-numeric: tabular-nums; }

.data-note {
  font-size: var(--fs-xs);
  color: var(--fg-low);
  padding-top: var(--space-3);
}
