﻿/* ==========================================================================
   TILGlobal premium refinement layer

   Loads after tilglobal-marketing.css and only refines finish: type rhythm,
   surface depth, interaction states and hero atmosphere. Colour still comes
   from tilglobal-tokens.css — nothing here introduces a new hue.

   Everything is scoped to body.tg-body so the LMS and admin are untouched.
   ========================================================================== */

body.tg-body {
  /* Fluid type scale, 1.25 ratio, clamped so it stays readable at both ends. */
  --tg-step--1: clamp(0.82rem, 0.79rem + 0.13vw, 0.89rem);
  --tg-step-0:  clamp(1rem, 0.96rem + 0.18vw, 1.09rem);
  --tg-step-1:  clamp(1.2rem, 1.12rem + 0.38vw, 1.45rem);
  --tg-step-2:  clamp(1.45rem, 1.31rem + 0.7vw, 1.95rem);
  --tg-step-3:  clamp(1.8rem, 1.53rem + 1.32vw, 2.6rem);
  --tg-step-4:  clamp(2.2rem, 1.74rem + 2.3vw, 3.5rem);

  /* Vertical rhythm */
  --tg-space-section: clamp(3.25rem, 2.2rem + 4vw, 6rem);

  --tg-serif: "Source Serif 4", Georgia, "Times New Roman", serif;

  font-size: var(--tg-step-0);
  line-height: 1.65;
  text-rendering: optimizeLegibility;
  -moz-osx-font-smoothing: grayscale;
}

/* --------------------------------------------------------------------------
   1. Typography
   -------------------------------------------------------------------------- */

body.tg-body h1,
body.tg-body h2,
body.tg-body h3 {
  line-height: 1.15;
  letter-spacing: -0.022em;
  text-wrap: balance;
}

body.tg-body h1 { font-size: var(--tg-step-3); font-weight: 800; }
body.tg-body h2 { font-size: var(--tg-step-2); font-weight: 800; }
body.tg-body h3 { font-size: var(--tg-step-1); font-weight: 750; letter-spacing: -0.014em; }

body.tg-body p { text-wrap: pretty; }

/* Section headings carry the serif — it is what makes the brand read as an
   institution rather than a marketplace. */
.tg-section-title,
.lobs-section-head h2 {
  font-family: var(--tg-serif);
  font-size: var(--tg-step-3);
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--tg-navy);
}

/* Standfirst under a section title: longer measure, lighter weight. */
.tg-section > .sub,
.tg-section-title + .sub {
  max-width: 62ch;
  font-size: var(--tg-step-1);
  font-weight: 550;
  line-height: 1.6;
  color: var(--tg-muted);
}

/* Eyebrows read as small caps labels, not shouty all-caps. */
.tg-eyebrow,
.lobs-eyebrow,
.tg-meta {
  font-size: var(--tg-step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Body copy should never run wider than a comfortable measure. */
.tg-mag-body p,
.cd-faq-body p,
.lobs-mag-body p { max-width: 72ch; }

/* Numerals in prices and data line up. */
.tg-price,
.cd-fee-price,
.tg-stat strong,
.lobs-stat strong { font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }

/* --------------------------------------------------------------------------
   2. Rhythm and spacing
   -------------------------------------------------------------------------- */

.tg-section { padding-block: var(--tg-space-section); }
.tg-band    { padding-block: var(--tg-space-section); }

.tg-section-title { margin-bottom: 0.5rem; }
.tg-section-title + .sub { margin-bottom: 2.25rem; }

/* --------------------------------------------------------------------------
   3. Surfaces and components
   -------------------------------------------------------------------------- */

.tg-item,
.tg-plus-feature,
.tg-tier-card,
.lobs-course-card {
  background: var(--tg-surface);
  border: 1px solid var(--tg-line);
  border-radius: var(--tg-radius-lg);
  box-shadow: var(--tg-shadow-sm);
  transition: transform 180ms cubic-bezier(0.2, 0.7, 0.3, 1),
              box-shadow 180ms cubic-bezier(0.2, 0.7, 0.3, 1),
              border-color 180ms ease;
}

.tg-item:hover,
.tg-plus-feature:hover,
.tg-tier-card:hover,
.lobs-course-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--tg-shadow-lg);
  border-color: var(--tg-line-strong);
}

/* A hairline of brand colour on hover reads as considered, not decorative. */
.tg-item { position: relative; overflow: hidden; }
.tg-item::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 3px;
  background: var(--tg-grad-action);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 220ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.tg-item:hover::after { transform: scaleX(1); }

/* Buttons: weight and depth, with a real pressed state. */
.tg-btn {
  font-weight: 720;
  letter-spacing: -0.01em;
  border-radius: var(--tg-radius-pill);
  transition: transform 140ms ease, box-shadow 140ms ease,
              background-color 140ms ease, color 140ms ease;
}

.tg-btn-primary {
  background: var(--tg-royal);
  color: #fff;
  box-shadow: 0 1px 2px rgba(11, 31, 58, 0.16), 0 8px 20px rgba(37, 99, 235, 0.22);
}
.tg-btn-primary:hover {
  background: var(--tg-royal-dark);
  box-shadow: 0 2px 4px rgba(11, 31, 58, 0.18), 0 14px 30px rgba(37, 99, 235, 0.3);
  transform: translateY(-1px);
}
.tg-btn-primary:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(11, 31, 58, 0.2); }

.tg-btn-ghost-light:hover { background: rgba(255, 255, 255, 0.12); }

/* Inputs feel like part of the same system as the buttons. */
.tg-search input,
.tg-search-hero input,
.lobs-home-search input {
  border: 1px solid var(--tg-line-strong);
  border-radius: var(--tg-radius-pill);
  background: var(--tg-surface);
  font: inherit;
  color: var(--tg-ink);
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.tg-search input::placeholder,
.tg-search-hero input::placeholder,
.lobs-home-search input::placeholder { color: var(--tg-faint); }
.tg-search input:focus,
.tg-search-hero input:focus,
.lobs-home-search input:focus {
  outline: none;
  border-color: var(--tg-royal);
  box-shadow: var(--tg-focus);
}

/* --------------------------------------------------------------------------
   4. Hero atmosphere
   -------------------------------------------------------------------------- */

.tg-hero,
.lobs-hero {
  position: relative;
  isolation: isolate;
  background: var(--tg-grad-hero);
  color: var(--tg-on-navy);
  overflow: hidden;
}

/* Two soft light sources: royal from the upper left, teal from the lower
   right. Subtle enough to read as depth rather than as a gradient. */
.tg-hero::before,
.lobs-hero::before {
  content: "";
  position: absolute;
  inset: -40% -10% auto -25%;
  height: 130%;
  z-index: -1;
  background:
    radial-gradient(52% 48% at 22% 18%, rgba(59, 130, 246, 0.32), transparent 68%),
    radial-gradient(46% 44% at 82% 88%, rgba(20, 184, 166, 0.22), transparent 70%);
  pointer-events: none;
}

/* Headings stay at full white — anything less makes the hero look washed out. */
.tg-hero h1,
.tg-hero h2,
.tg-hero h3,
.lobs-hero h1,
.lobs-hero h2,
.lobs-hero h3 { color: var(--tg-on-navy); }

.tg-hero .tg-eyebrow,
.lobs-hero .lobs-eyebrow { color: var(--tg-on-navy-muted); }

.tg-hero p,
.tg-hero li,
.lobs-hero p,
.lobs-hero li { color: var(--tg-on-navy-soft); }

.tg-brand-mark {
  font-family: var(--tg-serif);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.032em;
  color: var(--tg-on-navy);
}
.tg-brand-mark span { color: var(--tg-on-navy); }

/* Hero statistics sit on a glass panel rather than floating. */
.tg-stats {
  border-top: 1px solid var(--tg-on-navy-line);
  padding-top: 1.5rem;
}
.tg-stat strong { color: var(--tg-on-navy); font-size: var(--tg-step-2); font-weight: 800; }
.tg-stat span   { color: var(--tg-on-navy-faint); font-weight: 620; }

/* --------------------------------------------------------------------------
   5. Footer
   -------------------------------------------------------------------------- */

.lobs-footer h3 {
  font-size: var(--tg-step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tg-on-navy);
}
.lobs-footer__links a { transition: color 140ms ease; }
.lobs-footer__links a:hover { color: var(--tg-teal); }

/* --------------------------------------------------------------------------
   6. Respect reduced motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  body.tg-body *,
  body.tg-body *::before,
  body.tg-body *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .tg-item:hover,
  .tg-tier-card:hover,
  .lobs-course-card:hover { transform: none; }
}

/* ==========================================================================
   7. Brand marquee — the group's family of schools
   ========================================================================== */

.tg-brands { width: 100%; }

.tg-brands__viewport {
  display: flex;
  width: 100%;
  /* Without script this stays a plain horizontal scroller so every logo is
     still reachable; the live version hides the overflow and moves the track. */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  gap: 0;
  /* Fade the strip into the background at both edges instead of cutting it. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.tg-brands__viewport::-webkit-scrollbar { display: none; }

.tg-brands__track {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: clamp(2.5rem, 5vw, 5rem);
  margin: 0;
  /* The gap alone separates one set from the next, so no trailing padding:
     that would make the join wider than the spacing everywhere else and the
     loop would look uneven. */
  padding: 0;
  list-style: none;
  will-change: transform;
}

/* ---- Script has taken over ---- */

.tg-brands--live .tg-brands__viewport {
  overflow: hidden;
  /* Grabbable, and horizontal gestures belong to the strip while vertical ones
     still scroll the page. */
  cursor: grab;
  touch-action: pan-y;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}
.tg-brands--live.is-dragging .tg-brands__viewport { cursor: grabbing; }

/* Dragging by a logo should move the strip, not start a native image drag. */
.tg-brands--live .tg-brands__item img { -webkit-user-drag: none; pointer-events: none; }
.tg-brands--live .tg-brands__item a { pointer-events: auto; }

.tg-brands__item { flex: 0 0 auto; display: flex; align-items: center; }

.tg-brands__item a {
  display: flex;
  align-items: center;
  border-radius: var(--tg-radius-sm);
}

.tg-brands__item img {
  display: block;
  width: auto;
  height: clamp(30px, 3.4vw, 44px);
  max-width: 220px;
  object-fit: contain;
  transition: opacity 200ms ease, filter 200ms ease, transform 200ms ease;
}

/* Hovering or focusing pauses the scroll so a logo can be read or clicked.
   The live strip handles this in script, since the position is set per frame. */

/* ---- Light variant: pale surface, logos in their own colours ---- */
.tg-brands--light {
  background: var(--tg-surface);
  border-block: 1px solid var(--tg-line);
  padding-block: clamp(1.5rem, 2.5vw, 2.25rem);
}
/* Muted by default so the strip reads as one band rather than a colour clash,
   then full colour on hover. */
.tg-brands--light .tg-brands__item img {
  filter: grayscale(1);
  opacity: 0.62;
}
.tg-brands--light .tg-brands__item a:hover img,
.tg-brands--light .tg-brands__item a:focus-visible img {
  filter: grayscale(0);
  opacity: 1;
  transform: translateY(-2px);
}

/* ---- Dark variant: navy surface, each logo on a white chip ----
   Administrators upload logos in any format, including JPEG and GIF with an
   opaque background. Knocking those through to white would turn them into
   solid blocks, so instead every logo sits on its own white tile. That reads
   correctly on navy whatever the source file looks like. */
.tg-brands--dark {
  background: transparent;
  padding-block: clamp(1.25rem, 2vw, 1.9rem);
}
.tg-brands--dark .tg-brands__track { gap: clamp(1rem, 1.8vw, 1.75rem); }

.tg-brands--dark .tg-brands__item > a,
.tg-brands--dark .tg-brands__item > img {
  background: #FFFFFF;
  border-radius: 10px;
  padding: 0.6rem 1rem;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.18);
  opacity: 0.9;
  transition: opacity 200ms ease, transform 200ms ease;
}
.tg-brands--dark .tg-brands__item img { height: clamp(26px, 2.8vw, 36px); }

.tg-brands--dark .tg-brands__item > a:hover,
.tg-brands--dark .tg-brands__item > a:focus-visible {
  opacity: 1;
  transform: translateY(-2px);
}

/* ---- Section wrapper on the homepage ---- */
.tg-brands-section {
  background: var(--tg-surface);
  border-block: 1px solid var(--tg-line);
  padding-block: clamp(2.75rem, 4vw, 4.5rem);
}
.tg-brands-section .tg-brands--light {
  background: transparent;
  border: 0;
  padding-block: 0;
}
.tg-brands-head {
  max-width: var(--tg-max);
  margin: 0 auto clamp(1.75rem, 3vw, 2.5rem);
  padding-inline: 1.25rem;
  text-align: center;
}
.tg-brands-head .tg-eyebrow { color: var(--tg-royal); display: block; margin-bottom: 0.6rem; }
.tg-brands-head h2 {
  font-family: var(--tg-serif);
  font-size: var(--tg-step-3);
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--tg-navy);
  margin: 0 0 0.65rem;
}
.tg-brands-head p {
  max-width: 64ch;
  margin: 0 auto;
  color: var(--tg-muted);
  font-size: var(--tg-step-1);
  font-weight: 550;
  line-height: 1.6;
}

/* ---- Footer strip ----
   Sits between the link columns and the category list. Only a top rule is
   needed: the category list below already carries its own. */
.lobs-footer__brands {
  border-top: 1px solid var(--tg-on-navy-line);
  padding-top: clamp(1.5rem, 2.5vw, 2.25rem);
  margin-top: clamp(1.25rem, 2.5vw, 2rem);
  padding-bottom: clamp(1.25rem, 2vw, 1.75rem);
}
.lobs-footer__brands-label {
  display: block;
  text-align: center;
  margin-bottom: 1.1rem;
  font-size: var(--tg-step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tg-on-navy-muted);
}

@media (prefers-reduced-motion: reduce) {
  /* Script leaves the strip still, so it becomes a scrollable row that can be
     dragged deliberately rather than one that moves on its own. The duplicates
     stay, since they are what makes the drag continuous in both directions.
     The edge fade goes, because nothing is arriving from off screen. */
  .tg-brands__viewport,
  .tg-brands--live .tg-brands__viewport {
    -webkit-mask-image: none;
            mask-image: none;
  }
}

/* ==========================================================================
   8. Contrast hardening
   Accent colours are tuned as fills. Wherever the same colour is used for
   small text on a light surface it drops below WCAG AA, so it is swapped for
   the darker -text partner. Fills, borders and icons keep the brighter value.
   ========================================================================== */

/* Teal reads at 2.5:1 on white — unusable as text, fine as a fill. */
.tg-teal-text,
.tg-note--teal,
.tg-progress-label,
[data-accent="teal"] { color: var(--tg-teal-text); }

.tg-status-success, .tg-text-success { color: var(--tg-success-text); }
.tg-status-warning, .tg-text-warning { color: var(--tg-warning-text); }
.tg-status-danger,  .tg-text-danger  { color: var(--tg-danger-text); }

/* Links on light surfaces: royal at full strength is the action colour, but
   inline links inside body copy need the darker tone to sit comfortably
   against slate text. */
.lobs-section a:not([class]),
.tg-section a:not([class]),
.tg-prose a { color: var(--tg-royal-text); text-underline-offset: 2px; }

/* Struck-through original prices must stay legible, not vanish. */
s, del { color: var(--tg-faint); text-decoration-thickness: 1px; }

/* Placeholders sit one step above the disabled tone so the field still reads. */
::placeholder { color: var(--tg-faint); opacity: 1; }

/* Genuinely inert controls — the only place the palest grey is allowed. */
[disabled], .is-disabled, fieldset:disabled { color: var(--tg-disabled); }

/* Small print is the most common casualty of a pale palette: keep it at the
   readable tier rather than the caption tier. */
small, .tg-small, .tg-note, .sub { color: var(--tg-muted); }

/* Eyebrows: royal on light, white on navy. A pale blue passes contrast on navy
   but still reads as blue text on a blue panel, so dark surfaces get white and
   rely on size and letter-spacing for the hierarchy instead of hue. */
.tg-eyebrow, .lobs-eyebrow { color: var(--tg-royal-text); }
.tg-hero .tg-eyebrow, .lobs-hero .lobs-eyebrow,
.lobs-footer .tg-eyebrow, .tg-on-navy .tg-eyebrow { color: var(--tg-on-navy-muted); }

/* Any element sitting on navy inherits the on-navy scale. */
.tg-on-navy, .tg-panel--navy { color: var(--tg-on-navy-soft); }
.tg-on-navy h1, .tg-on-navy h2, .tg-on-navy h3,
.tg-panel--navy h1, .tg-panel--navy h2, .tg-panel--navy h3 { color: var(--tg-on-navy); }
.tg-on-navy a, .tg-panel--navy a { color: var(--tg-on-navy-link); }

/* ==========================================================================
   9. Programme page readability

   The programme layout has no sidebar, so its body column is much wider than
   a comfortable reading measure. Prose is capped; grids, charts and cards are
   deliberately left free to use the full column.
   ========================================================================== */

.lobs-mag-body > p,
.lobs-mag-body > ul,
.lobs-mag-body > ol:not(.lobs-modules),
.lobs-mag-body .cd-ai > p,
.lobs-mag-body .cd-ai > ul,
.lobs-mag-body .cd-ai > ol { max-width: 74ch; }

.lobs-mag-body .cd-faq-body p,
.lobs-mag-body .cd-faq-body ul { max-width: 82ch; }

/* Three across on very wide screens, two on the standard desktop. */
@media (min-width: 1180px) {
  .lobs-modules { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1500px) {
  .lobs-modules { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Charts need a real height or they collapse to a sliver. */
.cd-pro-chart-canvas { min-height: 320px; }
.cd-pro-charts:empty { display: none; }

/* Review statistics: even columns rather than four stretched cells. */
.cd-review-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; }

/* ==========================================================================
   10. Text on navy surfaces

   Royal blue is the correct eyebrow and link colour on a pale background, but
   it sits at roughly 2.6:1 on navy — the "blue text on a blue panel" problem.
   Previously each navy band worked around this with an inline hex on the
   element. Listing the navy surfaces once means the colour follows the
   surface, so a new band cannot reintroduce the fault.
   ========================================================================== */

/* Every navy or dark-gradient surface on the marketing site, listed once. The
   global "headings are navy" rule is a bare element selector, so any panel
   missing from this list gets a navy heading on a navy panel. Adding a new dark
   band means adding it here. */
.tg-dark-surfaces,
:is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .cd-cert, .lobs-marquee, .lobs-prog--ink,
    .lobs-sticky-bar, .lobs-footer, .tg-hero, .tg-cta-band, .tg-panel--navy, .tg-on-navy,
    .tg-a1, .tg-a2, .tg-a3, .tg-a4) { color: var(--tg-on-navy-soft); }

/* Each of these carries a leading `body` purely for specificity. Without it the
   rules tie with page-level ones such as `.lobs-body .lobs-eyebrow`, and whichever
   is declared last wins — which is how royal-blue eyebrows ended up on navy CTAs. */
body :is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .cd-cert, .lobs-marquee, .lobs-prog--ink,
    .lobs-sticky-bar, .lobs-footer, .tg-hero, .tg-cta-band, .tg-panel--navy, .tg-on-navy,
    .tg-a1, .tg-a2, .tg-a3, .tg-a4)
  :is(h1, h2, h3, h4, h5, h6, strong, b, dt) { color: var(--tg-on-navy); }

body :is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .cd-cert, .lobs-marquee, .lobs-prog--ink,
    .lobs-sticky-bar, .lobs-footer, .tg-hero, .tg-cta-band, .tg-panel--navy, .tg-on-navy,
    .tg-a1, .tg-a2, .tg-a3, .tg-a4)
  :is(p, li, dd, span, td, label) { color: var(--tg-on-navy-soft); }

body :is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .cd-cert, .lobs-marquee, .lobs-prog--ink,
    .lobs-footer, .tg-hero, .tg-cta-band, .tg-panel--navy, .tg-on-navy)
  :is(.lobs-eyebrow, .tg-eyebrow) { color: var(--tg-on-navy-muted); }

/* .tg-eyebrow is a pill with its own white fill. On a navy band that fill has to
   become glass, otherwise the light label is painted on white and vanishes. */
body :is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .lobs-prog--ink, .tg-hero, .tg-cta-band,
    .tg-panel--navy, .tg-on-navy) .tg-eyebrow {
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.24);
  color: var(--tg-on-navy);
}

body :is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .cd-cert, .lobs-marquee, .lobs-prog--ink,
    .tg-hero, .tg-cta-band, .tg-panel--navy, .tg-on-navy)
  :is(small, .small, .sub, .note, .text-muted) { color: var(--tg-on-navy-muted); }

/* A pale card deliberately placed on a dark band keeps its dark text.

   Every level has to be restated rather than left to inherit: the on-dark rules
   above match the card's descendants directly, so a white stat card inside a navy
   hero ends up with white numbers on a white panel. */
body :is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .cd-cert, .lobs-prog--ink, .tg-hero, .tg-cta-band)
  :is(.card, .cd-plan, .tg-item, .tg-stat, .tg-panel, .lobs-course-card) { color: var(--tg-body); }

body :is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .cd-cert, .lobs-prog--ink, .tg-hero, .tg-cta-band)
  :is(.card, .cd-plan, .tg-item, .tg-stat, .tg-panel, .lobs-course-card)
  :is(h1, h2, h3, h4, h5, h6, strong, b, dt) { color: var(--tg-navy); }

body :is(.lobs-hero, .lobs-home-hero, .lobs-mid-cta, .lobs-final-cta,
    .cd-cta-mid, .cd-cta-final, .cd-cert, .lobs-prog--ink, .tg-hero, .tg-cta-band)
  :is(.card, .cd-plan, .tg-item, .tg-stat, .tg-panel, .lobs-course-card)
  :is(p, li, dd, span, td, label, small, .sub, .note) { color: var(--tg-muted); }

/* A button sitting on a navy band paints its own fill, so anything inside it must
   take the button's label colour rather than the softened on-navy body tone. */
body :is(.lobs-btn, .lobs-btn-gold, .lobs-btn-ghost, .lobs-footer__cta,
         .tg-btn, .tg-btn-primary, .tg-btn-ghost, .sell-btn, .btn)
  :is(span, small, b, strong, em, i) { color: inherit; }

/* Plain links on navy. Buttons keep their own fill and label colour. */
.lobs-hero a:not([class]), .lobs-mid-cta a:not([class]),
.lobs-final-cta a:not([class]), .tg-hero a:not([class]),
.tg-panel--navy a:not([class]), .tg-on-navy a:not([class]) { color: var(--tg-on-navy-link); }

/* On a pale surface the eyebrow returns to royal, which reads at 6.7:1. */
.cd-fees .lobs-eyebrow,
.lobs-body .lobs-eyebrow { color: var(--tg-royal-text); }

/* ==========================================================================
   11. Career Insights charts

   ECharts draws inside a fixed box, so the card padding and the chart's own
   grid insets have to be set together or axis labels collide with the border.
   ========================================================================== */

.cd-pro-charts { gap: 2rem; margin-top: 2rem; }

.cd-pro-chart { padding: 1.5rem 1.5rem 1.25rem; }

.cd-pro-chart-head { margin-bottom: 1.1rem; padding-bottom: 0.9rem; }
.cd-pro-chart-title { font-size: 1.1rem; line-height: 1.4; }
.cd-pro-chart-sub { margin-top: 0.4rem; max-width: 70ch; }

.cd-pro-chart-canvas { margin-inline: -0.25rem; }

.cd-pro-chart-foot { margin-top: 1rem; padding-top: 0.85rem; max-width: 80ch; }

/* Narrow screens: less card padding, shorter charts, so the plot keeps a
   usable share of the width instead of being squeezed by the frame. */
@media (max-width: 640px) {
  .cd-pro-charts { gap: 1.35rem; margin-top: 1.35rem; }
  .cd-pro-chart { padding: 1.1rem 0.9rem 0.9rem; border-radius: 14px; }
  .cd-pro-chart-canvas { min-height: 280px; margin-inline: -0.5rem; }
}

/* ==========================================================================
   11. No blue text on navy

   Pale blues clear the contrast threshold on navy but still read as blue text
   on a blue panel, which is what they look like next to a white heading. Every
   label and heading on a dark surface is white here; only actual links keep a
   blue tint, because that tint is what marks them as links.
   ========================================================================== */

/* Course title, in the hero and in the bar that follows you down the page.
   Named explicitly so no two-class rule elsewhere can tint them. */
.lobs-hero h1#course-title,
.lobs-hero h1,
.lobs-sticky-bar .lobs-sticky-inner h3 { color: var(--tg-on-navy); }

/* Breadcrumbs: the trail and its separators, not decoration. */
.lobs-breadcrumb .sep { color: rgba(255, 255, 255, 0.62); }
.lobs-breadcrumb a { color: var(--tg-on-navy-muted); }
.lobs-breadcrumb a:hover { color: var(--tg-on-navy); }

/* Navy programme cards and the home hero highlight. */
.lobs-prog--ink .lobs-prog__level,
.lobs-prog--ink .lobs-prog__cta { color: var(--tg-on-navy-muted); }
.lobs-home-hero h1 .hl { color: var(--tg-on-navy); }
.tg-cta-band .tg-eyebrow { color: var(--tg-on-navy-muted); }

/* Footer: column headings, the strip label and the review stars sit on navy. */
.lobs-footer__stars { color: var(--tg-on-navy); }
.lobs-footer__contact a { color: var(--tg-on-navy); }
.lobs-footer__contact a:hover { color: var(--tg-on-navy-muted); }

/* Two-tone hero titles keep their emphasis, but in white rather than blue: the
   opening clause is softened and the phrase that matters stays full white. The
   span itself is set where it is defined, further up. */
.tg-brand-mark { color: var(--tg-on-navy-muted); }
