/* ==========================================================================
   tokens.css — the design system, and the only file you need for restyling.
   Everything is a CSS custom property. Change a value here and it changes
   everywhere on the site. No other file hardcodes a colour or a duration.

   HOW SIDES WORK
   There are two complete pages stacked on top of each other. The :root
   block below holds the LIGHT page's values; the .layer--dark block near the
   bottom re-declares only the tokens that differ, and it does so on the
   LAYER, so the dark page is dark at all times rather than only when it is
   the active one.

   data-side="light" | "dark" on <html> no longer picks a palette. All it
   does is decide where the curtain sits: --curtain, also near the bottom.
   ========================================================================== */

:root {

  /* --- Colour: surfaces -------------------------------------------------
     --bg           page background
     --card         the default card
     --card-tint    greige card (hero, ING)
     --card-strong  dark brown card (the big 80% / 60% numeral)
     --card-ink     black card (Booking, Writing)
     --accent       orange card (Presenter, 100%)
     --accent-soft  peach card (100% on the light side)
     Starting values are taken from the Figma screenshots; see PRD section 4.
  --------------------------------------------------------------------- */
  --bg:           #FFFFFF;
  --card:         #F4F3F1;
  --card-tint:    #E9DDD5;
  --card-strong:  #3B2F28;
  --card-ink:     #111111;

  /* TRYING OUT: a hairline on the neutral cards only - the plain grey one
     and the black --card-ink. The coloured surfaces (tint, strong, accent,
     accent-soft) stay borderless, so the line reads as definition on the
     neutrals rather than an outline on everything. Two values because the
     same grey needs more weight to show against a near-white card than
     against a near-black one. See .card border in site.css. */
  --card-line:    rgb(51 51 51 / 0.05);
  /* Grounds that exist only for the London Street Type sets, so six
     galleries in a row each land on a surface of their own. All three take
     white type on the clay (4.75:1), the umber (9.56:1) and the oxblood
     (10.67:1); the stone is a mid grey, so that one takes dark ink instead
     - white would be 2.76:1 on it, ink is 6.29:1. */
  --clay:         #8B6455;
  --stone:        #9C9391;
  --umber:        #4A3E30;
  --oxblood:      #542E2D;
  --accent:       #F26A1B;
  --accent-soft:  #F8D2B8;

  /* --- Colour: text -----------------------------------------------------
     Every text/background pair must clear WCAG AA (4.5:1 body, 3:1 large).
     If you change a surface above, re-check its ink token below.
  --------------------------------------------------------------------- */
  --ink:          #111111;  /* primary text on --bg and --card            */
  /* The barely-there secondary numeral. It is decorative - aria-hidden, with
     the figure carried by the card's visually-hidden heading - so no contrast
     rule applies and it is free to be this quiet. Warm rather than grey on
     purpose; .card--tint overrides it again in site.css. */
  --ink-ghost:    #E1D3CA;
  /* A shade deeper, for the ghost on a tinted card - and for the sweep
     across the dark cards' numerals, which wants the same warm grey. */
  --ink-ghost-tint: #D3C2B6;
  --ink-muted:    #5C5C5C;  /* secondary text, decks, captions            */
  --ink-on-tint:  #2B2622;  /* text on --card-tint                        */
  --ink-on-dark:  #F5F5F5;  /* text on --card-strong and --card-ink       */
  --ink-on-accent:#2B1405;  /* text on --accent / --accent-soft           */

  /* --- Colour: lines and focus ---------------------------------------- */
  --line:         #E4E4E4;  /* dividers, the curtain edge                 */
  --focus:        #F26A1B;  /* focus ring; 3px wide, 3px offset           */

  /* Selected text. The accent at full strength with the same dark brown it
     already carries on an orange card - a pairing the palette had already
     settled, and one that measures 5.69:1, comfortably over the 4.5:1 AA
     asks of body text. Both sides are opaque, so a selection reads the same
     on the white page, on the dark page and on any card between them, and
     the orange is the orange of the site rather than the browser's blue.
     Surfaces that are ALREADY this orange swap the pair - see site.css. */
  --select-bg:    #F26A1B;
  --select-ink:   #2B1405;
  /* The focus ring is orange sandwiched between a white and a near-black
     halo. Orange alone cannot clear 3:1 against every card colour on this
     site (it fails on white, and it is invisible on the orange card), so one
     of these two halos is always the one doing the work. Both are identical
     on both sides on purpose: the ring must not change meaning when the
     curtain moves. */
  --focus-halo-light: #FFFFFF;  /* the ring that shows on dark surfaces */
  --focus-halo-dark:  #111111;  /* the ring that shows on light surfaces */

  /* --- Typography -------------------------------------------------------
     Self-hosted in /fonts (see the @font-face rules at the top of
     site.css). Article prose runs on Raleway like the rest of the site:
     the serif that used to carry it was the one place the page changed
     voice, and it read as a different site rather than a quieter room.

     --font-body still exists as its own token because the typography
     chooser swaps it independently of --font-ui - picking Instrument, for
     instance, puts the serif on headings and the sans on prose. The two
     only happen to match here, in the default.
  --------------------------------------------------------------------- */
  --font-ui:   "Raleway", system-ui, -apple-system, sans-serif;
  --font-body: "Raleway", system-ui, -apple-system, sans-serif;

  /* The typography chooser (js/eggs.js) sets data-type on <html>; the
     blocks at the foot of this file swap the two families above. Raleway
     is the default and carries no attribute, so a page with the tool
     untouched is exactly the page that shipped. */

  /* Type scale. Anything that uses clamp() is fluid between mobile and
     desktop, so there are no breakpoint-specific font sizes to maintain. */
  /* The numerals are sized to fit a 420px card: "100%" is the widest string
     at roughly 2.8em, so 340px of content box divided by that is the ceiling.
     Raising --card-max means this can rise with it. */
  --fs-display:   clamp(4.5rem, 10vw, 9rem);    /*  72px -> 144px, the numerals   */
  /* The hero headline. Drawn at 32px, so that is the ceiling rather than a
     stop on the way up; it eases down to 28px on a phone. */
  --fs-headline:  clamp(1.75rem, 1.5rem + 1vw, 2rem);      /* 28px -> 32px */
  /* Card titles sit a step below the hero. They used to share --fs-headline
     and reached 40px, which put them ABOVE the 32px hero on a wide screen -
     the headline hierarchy upside down. Their own token now. */
  --fs-title:     clamp(1.375rem, 1.25rem + 0.7vw, 1.75rem); /* 22px -> 28px */
  --fs-body:      1.0625rem;                    /*  17px, card body               */
  --fs-lead:      0.9375rem;                    /*  15px, the hero paragraph      */
  --fs-caption:   1rem;                         /*  16px, stat captions           */
  --fs-label:     0.8125rem;                    /*  13px, LEADER. / DESIGNER.     */
  --fs-article:   1.25rem;                      /*  20px, article body            */
  --fs-case:      1.25rem;                      /*  20px, case-study body         */
  --fs-article-h2:2rem;                         /*  32px                          */

  /* Leading is unitless on purpose. A percentage resolves once, against the
     element's own size, and hands the resulting PIXEL value down to its
     children; a plain number is inherited as a number and re-resolves
     against whatever size each child ends up at. Same result here, correct
     result everywhere. Bigger type wants tighter leading, which is why
     there is more than one of these. */
  --lh-display:  0.9;
  --lh-tight:    1.1;    /* card titles, article and case subheads */
  --lh-headline: 1.3;    /* the hero headline, at 130%             */
  --lh-body:     1.5;
  --lh-lead:     1.7;    /* the hero paragraph, at 170%            */
  --lh-article:  1.6;

  --ls-headline: -0.01em;
  --ls-label:     0.12em;

  /* Extra air under the hero headline, on top of the card's own 0.75rem
     gap between children - the two together are the 22px you see. */
  --space-lead: 0.625rem;   /* 10px */

  --measure: 68ch;    /* article line length */

  /* --- Shape and spacing ----------------------------------------------- */
  --radius:      40px;   /* every card, and the sheet          */
  --radius-pill: 999px;  /* buttons, the curtain handle        */
  --toc-edge:    20px;   /* article contents: from the window's edge */
  /* The figure style for the typeface in use. Raleway overrides it below;
     the rest keep their own default. Everything that asks for tabular
     figures carries this alongside, because naming one part of
     font-variant-numeric resets the others. */
  --figures:     normal;
  --gap:         24px;   /* gap between rows; widens on desktop     */
  --gap-col:     24px;   /* gap between columns; widens on desktop  */
  /* How far the outer columns sit below the middle one. 40, not 64, so
     they land on a line of the 40px horizontal ruling the way the middle
     one does: at 64 the middle column's first card started on a rule and
     the outer two sat 24px past the next one down. */
  --col-offset:  40px;
  --pad:         24px;   /* card padding; 40px on desktop      */
  --card-max:    380px;  /* a column, and so a 1-wide card, never exceeds this */
  /* Page width is derived, not chosen: three columns, two gaps and the two
     side margins. Change --card-max or the desktop gap and this has to
     follow, or the columns stop landing on --card-max.                  */
  --page-max:    1332px; /* = 3*380 + 2*40 + 2*56              */
  --page-margin: 32px;   /* side margins                       */
  --tap:         44px;   /* minimum interactive target         */
  /* The header's vertical rhythm, as tokens rather than numbers buried in
     rules, because three separate things have to line up on it: the logo,
     the nav, and the minimised music player - which is fixed-position and
     so cannot just be a flex sibling of the other two. */
  --header-pad:  clamp(1.5rem, 4vw, 2.5rem);
  --logo-h:      2.75rem;
  /* The marks are cropped to their artwork, so each one paints at the full
     height of this box - that is what stops the hover swap changing the
     size of the wordmark. Their WIDTHS still differ, from 2.965 to 3.267
     times the height, so the box is fixed a shade past the widest and they
     sit inside it flush left. If a new mark is wider than 3.3, raise this
     or it will be scaled down to fit and break the equal height. */
  --logo-w: calc(var(--logo-h) * 3.3);

  /* Cards carry no shadow. Only the sheet and the curtain handle do. */
  --shadow-lift: 0 20px 60px rgb(0 0 0 / .25);

  /* --- The curtain --------------------------------------------------------
     --peek   how much of the far page stays visible at rest. Kept in px and
              kept well under --page-margin, so the sliver always sits in the
              page's own margin and never covers content. Raise it and the
              gutter has to rise with it.
     --seam   the gap between the two panels, where --backdrop shows through.
     --handle the grab target. Comfortably over the 44px minimum.
  --------------------------------------------------------------------- */
  --peek:      34px;
  --seam:       4px;
  /* The seam corners. Kept separate from --radius so the pages can read as
     bigger objects than the cards without dragging the cards along.

     The two sides are different on purpose. The light page's corner is a
     quiet 40px; the dark page's is a big 72px sweep, which is what gives the
     dark side the feeling of being one large object rather than a panel with
     a tidy edge. Measured off the Figma reference. */
  --radius-page:      40px;   /* light page, left corner  */
  --radius-page-dark: 72px;   /* dark page, right corner  */
  --handle:    52px;
  /* How far down the sheet starts, so the scaled-back page behind it stays
     visible above. It is what makes the sheet read as a card lifted off a
     stack rather than a new page. */
  --sheet-top: 20px;
  /* The uniform row height the bento layout packs to. A 1x1 card is one
     row; a 1x2 is two rows plus the gap between them. */
  --bento-row: 200px;
  --backdrop: #0D0D0D;   /* behind both pages: the gap and the seam corners */

  /* --- Motion -----------------------------------------------------------
     One easing curve for everything. No bounce, no overshoot.
     All three durations are forced to 0 under prefers-reduced-motion
     (see the bottom of site.css), so nothing here needs a media query.
  --------------------------------------------------------------------- */
  --ease-out:  cubic-bezier(0.2, 0, 0, 1);
  --dur-fast:  150ms;   /* hover, focus            */
  --dur-base:  400ms;   /* curtain via the buttons */
  /* The load sweep only. Its own pair because it is a reveal, not a
     response: 400ms is right for a button you just pressed and far too
     brisk for the page introducing itself. Changing --dur-base instead
     would slow the buttons down with it. Ease-in-out rather than the sharp
     --ease-out above, which over a whole second lunges and then crawls. */
  --dur-intro: 1000ms;
  --ease-intro: cubic-bezier(0.65, 0, 0.35, 1);

  /* The shape every gallery image is displayed in. Fixing the ratio is what
     makes a row of them share one height, whatever their source files
     happen to be - here they range from 1.79 to 2.15, an 85px difference in
     drawn height. 1.9 sits in the middle of that, so no one image is
     cropped much. See .gallery img in site.css for the crop itself. */
  --fig-ratio: 1.9;

  /* How wide one figure in a case-study gallery may get. Raised on desktop
     where the strip runs edge to edge - see .case in site.css. */
  --fig-max: 46rem;

  /* The drag handle's idle pulse. --ping-size is how far a ring grows as a
     multiple of the handle itself, so it follows --handle rather than being
     a second number to keep in step. The colour is set in site.css, because
     it depends on which side is showing. */
  --ping-size: 2.7;
  --ping-time: 2800ms;
  --dur-sheet: 450ms;   /* sheet open / close      */
}

/* --- The curtain --------------------------------------------------------
   ONE number drives the whole switch: the inset in the dark layer's
   clip-path, and the position of the handle you drag. Because both read the
   same property, the line and the edge it marks cannot drift apart.

   It is a position, not a proportion: the dark page runs from the left edge
   of the window to the seam, the light page from the seam to the right edge,
   and a --seam-wide gap between them lets the backdrop show through.

   Neither page ever disappears. --peek keeps a sliver of the other one
   visible at the far edge at all times, so the page always says there is
   something else to pull across.

   Registering it with @property is what makes it animatable - an ordinary
   custom property jumps rather than transitions. Browsers without @property
   (iOS 16.0-16.3) still switch, just instantly, which is the same thing
   reduced-motion asks for anyway.
   ----------------------------------------------------------------------- */
/* The stat fill. Registered so it can be TRANSITIONED - an unregistered
   custom property jumps from one value to the other, which is the whole
   point of this one. Same reason --curtain below is registered. */
@property --stat-stop {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

@property --curtain {
  syntax: "<length-percentage>";
  inherits: true;
  initial-value: 24px;
}

/* The seam corners. Both pages round on the SAME side at any moment, which
   is what keeps the gap between them an even strip instead of a crescent.
   Which side that is swaps as the curtain crosses over:

     curtain at the left   both round LEFT   the light page is the card,
                                             the dark sliver hugs its edge
     curtain at the right  both round RIGHT  the dark page is the card,
                                             the light sliver hugs its edge

   Registered so they can animate; the swap eases in over the last stretch
   of travel at each end rather than popping. */
@property --round-l {
  syntax: "<length>";
  inherits: true;
  initial-value: 40px;
}
@property --round-r {
  syntax: "<length>";
  inherits: true;
  initial-value: 0px;
}

:root {
  /* The seam, measured from the LEFT edge of the window. The dark page runs
     from the left edge up to it; the light page starts just after it. */
  --curtain: var(--peek);
  --round-l: var(--radius-page);
  --round-r: 0px;
  transition: --curtain  var(--dur-base) var(--ease-out),
              --round-l  var(--dur-base) var(--ease-out),
              --round-r  var(--dur-base) var(--ease-out);
}
[data-side="dark"] {
  --curtain: calc(100% - var(--peek));
  --round-l: 0px;
  --round-r: var(--radius-page-dark);
}

/* --- The load sweep -----------------------------------------------------
   Once a session the page opens with the curtain at the WRONG end and the
   transition declared above carries it across to the resolved side. These
   are the two starting positions: each one is the other side's rest state.

   data-side is already the RESOLVED side while this class is on, so inert,
   aria-hidden, the main landmark and the slider's value all describe the
   right page from the very first frame. Only the painted position is
   briefly the other one, and only for one frame before it starts moving.

   Same specificity as the rule above it, so this has to come after.
   The class is put on and taken off in the head of index.html.
   ----------------------------------------------------------------------- */
:root.is-intro {
  /* Resolved Leader: start at the Designer end and wipe the dark page away. */
  --curtain: calc(100% - var(--peek));
  --round-l: 0px;
  --round-r: var(--radius-page-dark);
  /* The handle's laid-out position stays at the destination the whole time;
     it only LOOKS like it travels, via the composited offset below. 100vw
     rather than 100% because a percentage inside translate would resolve
     against the handle's own 52px. It need only be right at the start of
     the sweep - it animates to 0, and 0 is the exact resting position - so
     the scrollbar's width being counted here changes nothing you can see. */
  --handle-x: var(--peek);
  --handle-dx: calc(100vw - 2 * var(--peek));
}
:root.is-intro[data-side="dark"] {
  /* Resolved Designer: start at the Leader end and wipe the light page away. */
  --curtain: var(--peek);
  --round-l: var(--radius-page);
  --round-r: 0px;
  --handle-x: calc(100% - var(--peek));
  --handle-dx: calc(2 * var(--peek) - 100vw);
}

/* The frame after .is-intro comes off, and for as long as the sweep runs.
   It keeps the handle's laid-out position pinned to the destination while
   --curtain animates past it, and lets --handle-dx fall to 0 so the handle
   glides there on the compositor. Both ease the same way over the same
   duration, so the handle sits exactly on the seam the whole way across.
   Dropped by the script in index.html once the sweep is over, and by
   js/curtain.js the moment anyone grabs the handle. */
:root.is-sweeping {
  --handle-x: var(--peek);
  --handle-dx: 0px;
  /* The sweep's own timing. This is the transition in force at the moment
     .is-intro comes off, so it is the one that carries the curtain across. */
  transition: --curtain  var(--dur-intro) var(--ease-intro),
              --round-l  var(--dur-intro) var(--ease-intro),
              --round-r  var(--dur-intro) var(--ease-intro);
}
/* The handle glides on the compositor rather than being laid out again, so
   it needs the same curve and the same second, or it stops sitting on the
   seam it is supposed to be holding. */
:root.is-sweeping .curtain__handle,
:root.is-sweeping .curtain__ping {
  transition: scale var(--dur-fast) var(--ease-out),
              translate var(--dur-intro) var(--ease-intro);
}
:root.is-sweeping[data-side="dark"] {
  --handle-x: calc(100% - var(--peek));
  --handle-dx: 0px;
}

/* While a finger or pointer is on the handle the curtain must track it
   exactly, with no easing lagging behind. */
:root.is-dragging { transition: none; }
/* The handle has a transition of its own for the sweep; a drag must not
   have to wait for it either. */
:root.is-dragging .curtain__handle,
:root.is-dragging .curtain__ping { transition: none; }

/* --- The dark page ------------------------------------------------------
   These belong to the LAYER, not to a state. The dark page is always dark,
   whether it is showing, hidden, or half revealed mid-drag - that is what
   lets the curtain sweep colour across the whole page in one move instead
   of the grid and its surroundings recolouring separately.

   Only the tokens that actually differ are listed; everything else is
   inherited from :root, which is why the two pages stay in sync by default.
   ----------------------------------------------------------------------- */
.layer--dark,
/* Standalone pages - case studies, articles, the writing index, 404 - have
   no layers at all; they carry data-side on <html> instead. The :not(:has())
   keeps this off the home page, where the palette belongs to the layer and
   data-side means only "where is the curtain". */
[data-side="dark"]:not(:has(.layer)) {
  --bg:        #131313;
  --card:      #1E1E1E;
  --card-ink:  #000000;
  --card-line: rgb(51 51 51 / 0.5);
  --ink:       #F5F5F5;
  --ink-muted: #A8A8A8;
  --ink-ghost: #2C2C2C;
  --line:      #2C2C2C;
  /* --card-tint, --card-strong, --accent and --accent-soft are deliberately
     identical on both sides: those cards are meant to read as the same
     object seen through the curtain. */
}

/* Below 1024px the handle is hidden and the curtain cannot be dragged, so
   the sliver is only a hint that there is another side - it does not have to
   be wide enough to grab. Keep it small enough to sit inside the gutter
   those widths use, or it covers the logo.

   The seam corner goes too: a big radius is a gesture that belongs to a
   curtain you can drag. With no drag it is just a bite out of the corner of
   a phone screen. */
@media (max-width: 63.99rem) {
  :root {
    /* No sliver at all. It existed to advertise a drag that does not happen
       here, and on a phone it reads as a stripe down the edge of the screen
       rather than a hint. The gap goes with it - with nothing peeking, a
       4px seam would just be a line of backdrop at the edge. */
    --peek: 0px;
    --seam: 0px;
    --radius-page: 0px;
    --radius-page-dark: 0px;
  }
}

/* Filtered, there is only one set of cards and no second side to go to, so
   the sliver of the far page is advertising a move that is not on offer -
   and the rounded corners are the join between two pages that are not both
   there any more. Same four tokens the phone zeroes, for the same reason:
   with nothing peeking, the seam is just a line of backdrop at the edge. */
:root.is-filtering {
  --peek: 0px;
  --seam: 0px;
  --radius-page: 0px;
  --radius-page-dark: 0px;
}

/* One column, and the card takes 90% of the screen. The gutter is what sets
   that: 5vw either side leaves exactly 90vw for the card. */
@media (max-width: 39.99rem) {
  :root { --page-margin: 5vw; }
}

/* The widest layout gets roomier cards and a much wider column gap: 60px
   between columns, while rows stay at 16px. This is the only spacing
   breakpoint, and it is the same one that turns on the third column - three
   420px columns with 60px gutters need this much room to breathe. */
/* Wherever the curtain is live, the page needs a wider gutter: the peeking
   sliver and the seam sit in it, and content must never end up underneath
   them. 56px leaves 18px of clear space beyond the 34px + 4px they take. */
@media (min-width: 64rem) {           /* 1024px */
  :root { --page-margin: 56px; }
}

@media (min-width: 80rem) {           /* 1280px */
  :root {
    --pad: 40px;
    /* The same number in both directions. The gap between two cards is 40px
       whichever way you measure it - there is no "column gap" idea on this
       page any more, just spacing. */
    --gap: 40px;
    --gap-col: 40px;
    /* 40 as well, so the mark occupies exactly one band of the horizontal
       ruling instead of overhanging it by 4px. Its top already landed on a
       rule; this is what puts its baseline on the next one down.

       It carries further than the logo. --logo-w is derived from it, so the
       mark's box narrows to match; the layout grid's own vertical ruling is
       drawn one line per --logo-h, which at 40 makes that lattice square
       against the 40px rules; and the header loses those 4px, which is what
       drops the grid below onto a rule as well. */
    --logo-h: 40px;
  }
}


/* --- The typography chooser --------------------------------------------
   Every selector here is :root-scoped on purpose. Written as a bare
   [data-type="..."] it also matches the chooser's own menu buttons, which
   carry that attribute to say which face they offer - and each one then
   redefined the tokens for its own subtree.

   One attribute on <html> swaps the two font roles the whole site is built
   on: --font-ui for everything, --font-body for article prose. Set before
   the first paint by a script in each page's <head>, and remembered for the
   session only, so a new tab always opens in Raleway.

   Four of the five are a single family doing both jobs. Instrument is a
   pair, which is the point of it.
   ----------------------------------------------------------------------- */
/* Raleway and Inter both read a size larger than the other three at the
   same number, so prose set in them comes down: 17px for an article where
   the others stay at 20, and 17px for a case study where the others stay
   at 18.

   Raleway is scoped by the ABSENCE of data-type, because that is how the
   chooser spells "default": it removes the attribute rather than writing
   one (see js/eggs.js). In rem, not px, so a reader's own font size still
   carries - 1.0625rem is 17px at the browser default. */
:root:not([data-type]) {
  --fs-article: 1.0625rem;                      /*  17px                          */
  --fs-case:    1.0625rem;                      /*  17px                          */
  /* Raleway ships old-style figures as its default: 3, 4, 5, 7 and 9 drop
     below the baseline and 0, 1, 2 sit at x-height, which reads as a typo
     in the middle of a sentence. The face carries lining figures too, so
     this is a switch rather than a substitution. The other four faces keep
     whatever they were drawn with - see --figures in the base block. */
  --figures: lining-nums;
}

:root[data-type="inter"] {
  --font-ui:   "Inter", system-ui, -apple-system, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, sans-serif;
  /* Same two steps down as Raleway above, for the same reason. */
  --fs-article: 1.0625rem;                      /*  17px                          */
  --fs-case:    1.0625rem;                      /*  17px                          */
}
:root[data-type="cormorant"] {
  --font-ui:   "Cormorant Garamond", Georgia, serif;
  --font-body: "Cormorant Garamond", Georgia, serif;
}
:root[data-type="jetbrains"] {
  --font-ui:   "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
  --font-body: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
}

/* The pair. Serif takes the display role - titles, headings, the big
   numerals - and Sans takes everything that is read rather than scanned:
   body copy, the secondary line on a card, article subtitles. */
:root[data-type="instrument"] {
  --font-ui:   "Instrument Serif", Georgia, serif;
  --font-body: "Instrument Sans", system-ui, -apple-system, sans-serif;
  /* Instrument Serif has one weight. Everything on this site asks for 600,
     and a browser answers that by smearing the 400 sideways into a fake
     bold, which on a high-contrast display serif looks broken. This turns
     the faking off: 600 simply renders as the 400 that exists. The Sans has
     real weights to 700, so it is unaffected. */
  font-synthesis-weight: none;
}

/* --- The serifs, tuned ---------------------------------------------------
   A display serif at the size a grotesque wanted is too quiet. Both serif
   faces get the same two sizes; nothing here leaks, so Raleway, Inter and
   the mono keep the tokens the design ships with.

   Every numeral, not just the lead one: .stat__value here is written with
   enough weight to beat both .card--stat-lead .stat__value and
   [data-size="1x1"] .stat__value, which each carry their own clamp.
   ------------------------------------------------------------------------ */
:root[data-type="instrument"] .hero__line,
:root[data-type="cormorant"]  .hero__line { font-size: 44px; }

/* Cormorant sets on a small body for its size, so the default 130% opens a
   gap between the lines at 44px. Instrument keeps the 130% - its own lines
   need the room. */
:root[data-type="cormorant"] .hero__line { line-height: 115%; }

/* The article index sets its titles smaller in the serifs: at the shared
   size these two run long and the cards stop reading as a grid of equal
   things. */
:root[data-type="cormorant"]  .post__title,
:root[data-type="instrument"] .post__title { font-size: 26px; }

/* Cormorant has a small x-height, so copy set at the site's usual sizes
   reads smaller than it measures. On the home grid the small copy comes up
   to a flat 20px.

   .layer is the scope: it exists only on the two home pages, so articles,
   the writing index, the case studies and the CV keep their own scale, and
   so does anything opened in the sheet (a <dialog> on <body>, outside both
   layers). The list's title goes up with its deck - leaving it behind would
   put the subtitle above the thing it belongs to. */
:root[data-type="cormorant"] .layer :is(
  .hero__body,
  .card__text,
  .stat__caption,
  .writing-list a,
  .deck
) { font-size: 20px; }

:root[data-type="instrument"] .stat__value,
:root[data-type="cormorant"]  .stat__value {
  font-size: 144px;
  /* --lh-display is 0.9, which is drawn for the grotesque. These two put
     roughly 1.21x their size on the page, so at 144px the ink stands 174px
     tall in a 129.6px line - 23px of it above the box and 21px below. The
     card clips to its own rounded edge, so that overhang came off the top
     of the numeral. This gives the line enough room to hold the glyphs and
     lets the card grow to suit. */
  line-height: 1.25;
}

/* Cormorant's TABULAR figures pad every digit out to one advance width, and
   the padding lands on the left: measured against the caption's first
   glyph, "1" starts 17.5px in at this size, "6" 8px, "8" 5px, while "2" and
   "4" start flush. So no single pull can square them - each numeral would
   need its own.

   Its proportional figures carry no left bearing at all: all five start at
   0.00px, exactly where the caption does. Tabular is for stacking figures
   in a column, and nothing here is in a column - these are single numerals
   on cards - so turning it off costs nothing and removes the problem at its
   source rather than correcting for it.

   The margin goes with it. That -0.044em is Raleway's bearing, measured for
   Raleway; against a zero bearing it would pull the numeral 6px PAST the
   text it is supposed to line up with. */
:root[data-type="cormorant"] .stat__value {
  font-variant-numeric: normal;
  /* Optical, not geometric - the same call the Raleway numerals get, and a
     different number because it is a different face. With the boxes now
     flush, a digit's leftmost ink is the curve of an 8 or a 0, while the
     caption below it usually opens on a letter whose serif foot reaches
     further left. Measured across the six cards at 144px, the numeral read
     about 5px indented. In em so it holds if the size changes. */
  margin-inline-start: -0.035em;
}

/* The title at the head of an article - the one on the page itself, not the
   one on a card that links to it. */
:root[data-type="instrument"] .article__title,
:root[data-type="cormorant"]  .article__title { font-size: 64px; }

/* The Sans carries what is read rather than scanned. Everything else on the
   page is already on --font-ui, so only these need naming. */
:root[data-type="instrument"] .hero__body,
:root[data-type="instrument"] .card__text,
:root[data-type="instrument"] .stat__caption,
:root[data-type="instrument"] .deck,
:root[data-type="instrument"] .post__deck,
:root[data-type="instrument"] .more__deck,
:root[data-type="instrument"] .article__deck,
:root[data-type="instrument"] .case__lede,
:root[data-type="instrument"] .writing-index__lede,
:root[data-type="instrument"] .gallery figcaption,
:root[data-type="instrument"] .figure figcaption {
  font-family: var(--font-body);
}
