/* ==========================================================================
   00-TOKENS.CSS — single source of truth for every visual value.
   ==========================================================================

   Authority: STEP 2C section I, APPROVED HOMEPAGE DESIGN CONTRACT.

   Status legend used in the comments below:
     [LOCKED]  structural value, measured from the approved reference and fixed
               by the contract. Do not change without sign-off.
     [REF]     reference-derived: sampled from the approved image. Canonical for
               implementation, pending written client ratification of the
               palette (blocker J-1 / BLOCK-5).
     [PROV]    provisional: not derivable from the reference. Must be revisited.
               Marked in code so it cannot pass silently.

   RULES
     1. No component stylesheet may contain a literal hex, px radius, px space
        value or shadow. Everything resolves to a custom property here.
     2. Only these radii exist: 4 / 8 / 12 / full. No stray 6 or 16.
     3. White text on the accent colour is forbidden. Use --color-accent-on.
     4. Section vertical padding uses the PRODUCTION values below, not values
        back-calculated from the reference image (a compressed full-page
        composite — see the measurement caveat in STEP 2C).
   ========================================================================== */

:root {
  /* ---------------------------------------------------------------- colour
     Navy scale — structure and authority. [REF] */
  --color-primary-900: #031932; /* utility bar, footer           [REF] */
  --color-primary-800: #012146; /* hero gradient origin          [REF] */
  --color-primary-700: #002a5e; /* primary navy: CTA band, cards [REF] */
  --color-primary-600: #003c81; /* solid navy button fill        [REF] */
  --color-primary-500: #1263bb; /* eyebrow labels, inline links  [REF] */
  --color-primary-100: #e3edf8; /* tinted surfaces, focus halo   [REF] */

  --color-primary: var(--color-primary-700);
  --color-primary-dark: var(--color-primary-900);
  --color-primary-light: var(--color-primary-500);

  /* Accent — wayfinding only. Five sanctioned roles, never a field. [REF] */
  --color-accent: #fbba1a;
  --color-accent-hover: #e5a50f;
  --color-accent-strong: #fed216; /* thin indicators: nav underline, dot */
  --color-accent-on: #0b0a16;     /* text on accent. NEVER white.        */

  /* Surfaces and text */
  --color-background: #ffffff;
  --color-surface: #ffffff;
  --color-surface-alt: #f7f8fa; /* alternating band background     [REF] */
  /* Cool institutional tint for the one elevated light surface on the page.
     Sits between white and --color-primary-100 so the principal's tint band
     separates from the white bands around it without becoming a colour field.
     [REF, derived from --color-primary-100 at low saturation] */
  --color-surface-tint: #f4f8fd;

  --color-text-primary: #0f1724;
  --color-text-secondary: #3b4149;
  --color-text-muted: #5b6066;
  --color-text-on-dark: #ffffff;
  --color-text-on-dark-muted: #dee3e9;

  /* The plate a faculty portrait sits on. It is a SURFACE, not a tint: three of
     the four homepage portraits are background-removed PNGs with a genuinely
     transparent field (verified per-pixel, all four corners alpha=127), so
     whatever sits behind them IS the visible backdrop of the photograph. The
     reference's placeholder portraits are studio shots on a neutral grey
     backdrop measuring #e9e8e8; this is that value moved into the page's cool
     neutral family so it agrees with --color-border / --color-surface-alt.

     Deliberately neutral rather than --color-primary-100: the fourth portrait is
     a flattened JPEG with its own background, and a coloured plate would render
     it as a photograph-shaped rectangle inside a tinted frame. [REF, sampled] */
  --color-photo-plate: #ebedf0;

  /* Warm surface for the lead faculty card's service-record tiles. The accent
     family at very low saturation, so the card can set "what they study" (the
     cool --color-primary-100 research panel) against "service record" (these
     warm tiles) without introducing a second border weight to separate them.
     Measured on it: navy-700 13.1:1, --color-text-primary 16.7:1.
     [REF, sampled from the approved single-card faculty reference] */
  --color-surface-accent: #fdf6e7;

  /* Borders. Functional, not decorative: programme cards are white-on-white
     and legible only by their border. Do not lighten. [REF] */
  --color-border: #e3e4e7;
  --color-border-subtle: #eff1f3;
  --color-border-on-dark: rgba(255, 255, 255, 0.24);
  /* Gold hairline. NOT a sixth accent role: it is --color-accent held back to
     border weight so a credential chip can be outlined in the accent family
     without the saturated accent reading as a filled field, which the accent
     rules forbid. Used for outlines only, never for text or a fill.

     It is 1.42:1 against white, so it is DECORATIVE and never load-bearing: the
     chips it outlines are legible from their own fill and their navy text
     (13.1:1), and the tile labels it underlines are legible without the rule.
     Nothing on the card depends on this border being seen. [REF, sampled from
     the approved single-card faculty reference] */
  --color-border-accent: #f0d69a;

  /* Header pass — client-directed premium institutional header. The two navy
     bands of the header (information bar, navigation row) use the client's
     specified institutional navy, one step bluer than the locked page navy;
     scoped to the header so the hero, bands and footer keep the locked scale. */
  --color-header-navy: #06264a;
  --color-header-masthead: #fcfbf7; /* ivory branding row surface */

  /* Status. Error is reference-derived from the "New" notice badge. Success
     and warning are NOT in the reference: form/admin feedback only. */
  --color-error: #e11d0b;   /* [REF]  */
  --color-success: #15803d; /* [PROV] */
  --color-warning: #b45309; /* [PROV] */

  /* Programme category tints. The reference is inconsistent about whether the
     icon tile is a saturated fill or a pale tint; standardised here on pale
     tint + saturated glyph so glyph contrast is guaranteed.
     [REF, normalised — the one place the reference was not copied literally] */
  --color-cat-1-bg: #e4eefb;
  --color-cat-1-fg: #0a4999;
  --color-cat-2-bg: #e6f4e7;
  --color-cat-2-fg: #1f7a34;
  --color-cat-3-bg: #fdeed7;
  --color-cat-3-fg: #b4560a;
  --color-cat-4-bg: #f1e6f5;
  --color-cat-4-fg: #7c2097;
  /* Unmapped taxonomy terms fall back to navy, never to a random hue. */
  --color-cat-default-bg: var(--color-primary-100);
  --color-cat-default-fg: var(--color-primary-600);

  /* ------------------------------------------------------------ typography
     PROVISIONAL FAMILY. Inter has not been supplied (blocker J-3) and this
     theme must never contact a font CDN. Until assets/fonts/ is populated the
     stack below resolves to the platform UI sans — metrically close enough to
     keep layout honest while remaining visibly not-final. Do not substitute a
     different visual system to "fill the gap".  [PROV] */
  --font-sans:
    "Inter",
    system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
    sans-serif;

  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;

  /* Fluid sizes: clamps, not breakpoint jumps. Upper bounds [LOCKED]. */
  --text-display: clamp(1.875rem, 1.2rem + 2.6vw, 3rem); /* 30 -> 48 */
  --text-h1: clamp(1.75rem, 1.3rem + 1.8vw, 2.5rem);     /* 28 -> 40 */
  --text-h2: clamp(1.5rem, 1.3rem + 0.8vw, 1.75rem);     /* 24 -> 28 */
  --text-h3: clamp(1.1875rem, 1.1rem + 0.4vw, 1.375rem); /* 19 -> 22 */
  --text-body-lg: 1.0625rem; /* 17 */
  --text-body: 1rem;         /* 16 — never reduced on mobile [LOCKED] */
  --text-sm: 0.875rem;       /* 14 */
  --text-xs: 0.75rem;        /* 12 — metadata floor */
  --text-ui: 0.8125rem;      /* 13 — nav, buttons, eyebrows */

  /* Header pass. The masthead department line and the navigation labels sit
     between the existing steps, so they get their own tokens rather than
     borrowing a size that also styles body copy elsewhere. */
  /* Polish pass: capped a step lower (30 max, down from 32) so the department
     line stays the dominant identity without reading oversized. */
  --text-masthead-title: clamp(1.4375rem, 1.25rem + 0.7vw, 1.875rem); /* 23 -> 30 */
  --text-nav-link: 0.9375rem; /* 15 — header navigation labels */

  /* Polish pass: the hero headline's own size and leading. One step below
     --text-display (~15% smaller, per the client's 12–18% window) and a
     notch tighter than the display leading, so the banner text block feels
     strong but not oversized. Scoped to the hero: the other display-sized
     headings on the site keep --text-display / --leading-display. */
  --text-hero-display: clamp(1.625rem, 1.05rem + 2.3vw, 2.5625rem); /* 26 -> 41 */
  --leading-hero: 1.06;

  /* The faculty profile's h1: the masthead is that page's hero and the name is its
     headline, so it sizes above the ordinary page h1 — 28 at phone widths, exactly
     34 by 768 (tablet), 42 at 1280 and up to the 50px display ceiling — while
     staying inside the display ceiling. Scoped to .c-profile__name; no other
     page's h1 changes. */
  --text-profile-name: clamp(1.75rem, 1.375rem + 1.5625vw, 3.125rem); /* 28 -> 50 */

  /* The biography's relaxed measure: the profile's long-form read sits a touch
     looser than --leading-body so three paragraphs of institutional history
     stay comfortable without becoming airy. Scoped to .c-profile__bio. */
  --leading-prose-relaxed: 1.75;

  /* The heritage-year watermark in the founder band's document card: one
     oversized numeral, bigger than the scale goes because it is a watermark
     and must never read as a heading. Fixed rather than clamped: it only
     renders from 1200px, where the card's interior is wide enough to hold it
     clear of the lead's measure. [PROV] */
  --text-heritage-year: 7rem;

  --leading-display: 1.1;  /* [LOCKED] */
  --leading-heading: 1.25; /* [LOCKED] */
  --leading-body: 1.6;     /* [LOCKED] */
  --leading-flat: 1;

  --tracking-display: -0.01em;
  --tracking-ui: 0.04em;
  --tracking-eyebrow: 0.08em;
  --tracking-wide: 0.12em;

  --measure-body: 62ch; /* line-length cap */
  --measure-lead: 46ch;

  /* ----------------------------------------------------------------- space
     4px base, 8px preferred increments. */
  --space-3xs: 0.125rem; /* 2  */
  --space-2xs: 0.25rem;  /* 4  */
  --space-xs: 0.5rem;    /* 8  */
  --space-sm: 0.75rem;   /* 12 */
  --space-md: 1rem;      /* 16 */
  --space-lg: 1.5rem;    /* 24 */
  --space-xl: 2rem;      /* 32 */
  --space-2xl: 3rem;     /* 48 */
  --space-3xl: 4rem;     /* 64 */
  --space-4xl: 6rem;     /* 96 */

  /* Section rhythm — PRODUCTION values, 96/64/48. [LOCKED] */
  --space-section: var(--space-4xl);

  /* ---------------------------------------------------------------- radius
     --radius-btn is the button system's own corner: one step rounder than
     --radius-sm, matching the subtle 5-6px corner the approved reference
     puts on outlined actions. Buttons reach it through the --btn-radius
     hook; --radius-sm stays 4px for the tighter chips. */
  --radius-btn: 6px;    /* buttons — the c-btn system              */
  --radius-sm: 4px;     /* chips, tight badges                     */
  --radius-md: 8px;     /* cards, inline images                    */
  --radius-lg: 12px;    /* principal card, icon tiles              */
  /* The trust strip's institutional panel: one step rounder than the cards it
     sits above, inside the 14-18px window a standalone premium information bar
     carries in the approved reference. */
  --radius-xl: 16px;    /* trust strip                             */
  --radius-full: 999px; /* carousel arrows, badges, dots           */

  /* ---------------------------------------------------------------- shadow
     Soft, wide, low-opacity falloff. --shadow-md is measured from the
     reference's edge blur; --shadow-lg is the one panel that needs the deeper
     falloff — the trust strip, which straddles the hero and must still read as
     a raised panel against navy, where a light falloff disappears. [REF] */
  --shadow-sm: 0 1px 3px rgba(3, 25, 50, 0.08);
  --shadow-md: 0 8px 24px rgba(3, 25, 50, 0.08);
  --shadow-lg: 0 16px 40px rgba(3, 25, 50, 0.12);

  /* Header pass: the single shadow under the navigation row. From the brief
     (0 4px 16px rgba(6,38,74,.10)) — keyed to the header navy, not the page
     navy, so the falloff and the bar it falls from agree. */
  --shadow-header: 0 4px 16px rgba(6, 38, 74, 0.1);

  /* Solid offset "mount board" behind the founder portrait plate. Not an
     elevation falloff at all: a flat primary-100 rectangle that peeks past
     the plate's lower corner, so the hung picture reads as mounted on a
     board rather than floating on the band. Expressed as a box-shadow
     because that is the only CSS layer that paints behind an element's own
     background without adding a wrapper to the markup. [PROV] */
  --shadow-mount: var(--space-sm) var(--space-sm) 0 0 var(--color-primary-100);

  /* ---------------------------------------------------------------- layout
     Container 1280 measured as 912 reference px x 1.40625. [LOCKED] */
  --container-width: 1280px;
  --container-gutter: var(--space-lg);
  --utility-height: 44px; /* header pass: 42–46px brief window */

  /* Header. The header is two rows: an identity masthead over a navigation bar.
     --header-height is their sum and remains the documented full height; the
     two component heights are what the rows actually set. On scroll the
     identity row is removed, so the sticky height is the nav row alone —
     which is what --header-height-sticky now means.
     [Revised by the client-directed header pass: 116 + 68; the original
     contract sum was 88 + 48. Polish pass: masthead tightened to 104
     (a ~10% vertical reduction), crest to 68 and founder to 56 stepping
     down with it, so the plain white header reads compact, not airy.] */
  --header-identity-height: 104px;
  --header-nav-height: 68px;
  --header-height: calc(var(--header-identity-height) + var(--header-nav-height));
  --header-height-sticky: var(--header-nav-height);
  --header-height-mobile: 64px;
  /* The crest is bounded by height, never by width: the supplied file is a
     transparent PNG whose proportions must not be forced. */
  --header-logo-height: 68px;
  /* Founder portrait in the masthead, 58–70px per the brief. The divider
     beside it reuses this so the rule is the block's height, not the row's. */
  --header-founder-size: 56px;

  /* Trust strip overlap. The strip is pulled up by this much so it straddles
     the hero's lower edge — the one place on the page where a component crosses
     a band boundary, so the amount is a token rather than a magic number.
     64px on desktop sits in the approved 56–72px window: enough that the strip
     reads as attached to the hero, not enough to cover the hero's CTAs.
     Stepped down at 1023 and removed at 767, below the media queries. */
  --trust-overlap: 64px;

  --tap-target: 44px; /* minimum interactive size [LOCKED] */
  /* WCAG 2.2 target size (minimum) floor. Used where a control is deliberately
     small in the design (breadcrumbs, inline meta links) and cannot take the
     full 44px comfort target. */
  --tap-target-min: 24px;

  /* ---------------------------------------------------------- aspect ratio
     All measured from the reference. [LOCKED] */
  --ratio-hero: 16 / 9;
  --ratio-hero-mobile: 4 / 5;
  --ratio-wide: 21 / 9;    /* page + single hero strips [see note below] */
  --ratio-faculty: 3 / 2;  /* gallery tiles — see note below */
  --ratio-faculty-portrait: 4 / 5; /* faculty PROFILE portrait */
  --ratio-faculty-card: 1 / 1;     /* faculty CARD plate — see note below */
  --ratio-portrait: 4 / 5; /* principal                    */
  --ratio-map: 16 / 9;

  /* --ratio-faculty no longer applies to the faculty card. Eleven of the twelve
     supplied faculty photographs are portrait-orientation, 0.69:1 to 0.93:1, and
     most are transparent background-removed cut-outs. A 3:2 landscape plate fed
     by the 'tdc-faculty' image size — add_image_size( 480, 320, true ), a HARD
     CROP — discarded roughly half of each portrait's height in the file itself
     and cut the heads off.

     The 3:2 token stays exactly as measured because the gallery strip still uses
     it: there, a shared landscape frame is what keeps a row of mixed legacy
     photographs from looking ragged.

     TWO FACULTY RATIOS NOW EXIST, and they are not interchangeable:

       --ratio-faculty-portrait  4:5   the PROFILE page's 280px portrait
       --ratio-faculty-card      1:1   the CARD's plate

     The card's frame is the card's full width — 255px in the homepage showcase,
     290px on the archive — so at 4:5 it would be 319px/363px tall before a single
     line of text. 1:1 is the shortest frame every one of the twelve sources
     tolerates: probe-portrait-vertical.php measured, per file, the widest frame
     that still contains the head and the top of the shoulders once object-fit:
     cover has filled it, and the binding constraint is Dr. Seemant kumar Ray at
     1.05:1. 5:4 (1.25) would cut the shoulders off five of the twelve.

     The profile page keeps 4:5 because its portrait is a fixed 280px column, not
     a full-width plate, so height there is not the constraint. */

  /* --ratio-wide no longer applies to the About band. The reference measured
     2.32:1 there, but the actual photograph the client supplied is a 1.53:1
     group shot, and imposing 21:9 on it cut people out of the top and bottom
     edges. About now uses .c-media--natural (no ratio). The token stays as
     measured for the page and single templates, which use editorial strips. */

  /* ------------------------------------------------------------ transition
     transform and opacity only. Nothing animates layout properties. */
  --duration-fast: 150ms;
  --duration-base: 200ms;
  --duration-slow: 400ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --transition-base: var(--duration-base) var(--ease-out);

  /* ------------------------------------------------------------ focus ring
     2px, 2px offset, on everything focusable. Gold variant on dark bands. */
  --focus-width: 2px;
  --focus-offset: 2px;
  --focus-color: var(--color-primary-600);
  --focus-color-on-dark: var(--color-accent-strong);

  /* --------------------------------------------------------------- z-index */
  --z-base: 1;
  --z-header: 100;
  --z-dropdown: 110;
  --z-drawer: 120;
  --z-overlay: 130;
  --z-lightbox: 140;
}

/* Gutter and section rhythm step down with viewport, as tokens. */
@media (max-width: 1023px) {
  :root {
    --container-gutter: 1.25rem;       /* 20 */
    --space-section: var(--space-3xl); /* 64 */

    /* Below the drawer breakpoint the navigation row is removed and the
       identity row is what stays stuck, so the sticky height — which
       scroll-padding-top is derived from — is the identity row's height. */
    --header-height-sticky: var(--header-height-mobile);

    /* The crest steps back to its pre-header-pass size: the mobile identity
       row is 64px and a 68px crest would overflow it. */
    --header-logo-height: 56px;

    /* Tablet: the strip is two rows tall here, so a full 64px lift would push
       the second row over the hero text. 48px keeps the attachment legible. */
    --trust-overlap: 48px;
  }
}

@media (max-width: 767px) {
  :root {
    --container-gutter: 1rem;          /* 16 */
    --space-section: var(--space-2xl); /* 48 */

    /* No overlap on mobile: the strip becomes a normal in-flow card. A card
       hanging over the hero on a 390px viewport reads as a rendering fault,
       and the hero's stacked CTAs occupy the space the overlap would take. */
    --trust-overlap: 0px;
  }
}

/* Honour the OS motion preference at token level, so every component using
   --transition-base is covered without repeating the media query. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 1ms;
    --duration-base: 1ms;
    --duration-slow: 1ms;
  }
}
