/* ============================================================================
   Shared components. Every repeated element on the site lives here exactly once.
   Page-specific CSS goes in assets/css/pages/*.css and is capped at 200 lines
   (enforced by scripts/check-css-size.mjs): the third variant of anything
   belongs in this file instead.
   ========================================================================== */

/* --- typography ---------------------------------------------------------- */

h1, h2, h3, h4 {
  line-height: var(--lh-tight);
  font-weight: var(--fw-bold);
  color: var(--c-ink);
  text-wrap: balance;
}

h1 { font-size: var(--t-3xl); }
h2 { font-size: var(--t-2xl); }
h3 { font-size: var(--t-xl); }
h4 { font-size: var(--t-lg); }

/* The brand orange is the rule under the link, not the link's colour. As text
   it is 2.33:1 on a card; as a decoration it carries no contrast requirement,
   while the ink underneath measures 14.15:1. That is the only way this site
   can show #ff8c00 in running text at all. */
a {
  color: var(--c-link);
  text-decoration: underline;
  text-decoration-color: var(--c-link-rule);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

a:hover {
  text-decoration-thickness: 3px;
}

.eyebrow {
  display: block;
  font-size: var(--t-xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--c-ink-muted);
  margin-block-end: var(--s-3);
}

.lede {
  font-size: var(--t-lg);
  color: var(--c-ink-muted);
  /* ch is relative to the element's own font, so a plain var(--measure) at
     --t-lg ran 12.5% wider than the 16px prose and photograph beneath it, and
     the lede's right edge stuck out about 90px past theirs. 16/18 is
     --t-base over --t-lg, which brings it back to the body's line. */
  max-width: calc(var(--measure) * 16 / 18);
}

.section-heading {
  margin-block-end: var(--s-6);
}

/* --- buttons -------------------------------------------------------------- */

.button {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-5);
  border-radius: var(--radius);
  border: 2px solid transparent;
  font-weight: var(--fw-medium);
  text-decoration: none;
  cursor: pointer;
}

/* Two variants, and the border belongs to the variant rather than to the
   palette: a filled button draws its border in its own fill, so there is no
   edge to see, and an outlined button draws a visible one. Both keep the 2px
   so the pair sits at the same height side by side.

   What that costs, measured and accepted: the orange fill is 1.96:1 against
   the page and 1.79:1 against a band, under the 3:1 WCAG 1.4.11 asks of a
   control's boundary. The ink outline that used to buy it made the same
   button look like a different component on every ground, and the only orange
   dark enough to pass is the brown this palette already threw out. The label
   inside is the ink at 6.06:1 and the fill is the brand colour, which is the
   point of it.

   Hover inverts rather than darkening: there is no darker orange to go to. */
.button--primary {
  background: var(--c-brand-orange);
  color: var(--c-ink);
  border-color: var(--c-brand-orange);
}

.button--primary:hover {
  background: var(--c-ink);
  color: var(--c-focus-light);
  border-color: var(--c-ink);
}

.button--secondary {
  background: var(--c-surface);
  color: var(--c-ink);
  border-color: var(--c-ink);
}

.button--secondary:hover {
  background: var(--c-surface-alt);
  color: var(--c-ink);
}

/* On a photograph the outlined button takes the light edge: the ink measures
   1.19:1 against the scrim on a mid pixel and 2.48:1 at the worst case, so it
   is a dirty fringe rather than a boundary. White is 5.71:1 at that worst case.

   Both hovers go to white for the same reason. Inverting the filled button to
   the ink here puts a 1.19:1 fill on the picture, which erases the button and
   leaves the label floating. */
.hero .button--secondary {
  background: transparent;
  color: var(--c-focus-light);
  border-color: var(--c-focus-light);
}

.hero .button--primary:hover,
.hero .button--secondary:hover {
  background: var(--c-focus-light);
  color: var(--c-ink);
  border-color: var(--c-focus-light);
}

.button-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}

/* The navigational link that closes a section, as opposed to an action. Kept a
   link rather than promoted to a button: the homepage would otherwise carry
   four competing buttons and the primary one would stop meaning anything.
   See the buttons and links table in docs/design-system.md. */
.link--more {
  display: inline-block;
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.link--more:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Decorative: the link text already says where it goes, so the arrow must not
   be read out as "rightwards arrow". The `/ ""` alt syntax does that properly.
   The plain declaration first means an older browser still draws the arrow;
   one that understands the alt text uses the second and announces nothing. */
.link--more::after {
  content: " \2192";
  content: " \2192" / "";
}

/* The row that closes a section, whether it holds a trailing link or buttons.
   The reset zeroes paragraph margins, so without this a trailing <p> sits flush
   against the grid above it. This replaces three hand-written inline margins. */
.section-actions {
  margin-block-start: var(--s-6);
}

/* A heading that opens a second part of the same page, such as Past events. */
/* A heading that opens a second part of the same page, such as "Still to come"
   on /resources/. It needs space above it to separate it from the previous part
   and a little below so it is not flush against the table or grid it labels.

   Design SIG reported "spacing under resources needs fixing". The cause was
   .about-section being used on those headings, which only sets margin-block-END,
   so each heading was pushed 4rem away from the content it introduces and sat
   hard against the content above it. Exactly backwards. */
.subsection {
  margin-block-start: var(--s-7);
  margin-block-end: var(--s-4);
}

/* The first such heading on a page wants the space underneath but not above,
   because the page header already provides that. */
.resources-heading {
  margin-block-end: var(--s-4);
}

/* Photographs in an article body take the same corner as every other surface
   on the site. Without this the same photograph is rounded as a card thumbnail
   on /news/ and square in the article it belongs to, which is the sort of
   mismatch that reads as an unfinished page rather than as a choice.

   Not every img: a logo or an emblem inside prose should keep its own shape,
   and the full-bleed bands (hero, title band, facts) stay square because a
   rounded edge on an element that runs to the viewport edge has nothing to sit
   against. */
.post__image,
.prose img {
  border-radius: var(--radius);
}

/* width and height, because the image transform writes the file's own
   width="1600" height="1059" onto the <img>. The reset's max-width clamps the
   width to the column, but the attribute height survived, so a 3:2 photograph
   rendered 726 by 1059 on a desktop and 358 by 1059 on a phone: squashed
   sideways, and blurry too, because the browser picks the file by the clamped
   width and then stretched it to the full height. The same failure the partner
   logos had, see .partner-card__logo img. */
.post__image {
  width: 100%;
  height: auto;
}

/* The <figure> the lead photograph sits in. The reset zeroes every <figure>, and
   this one is a direct child of .container with no stack around it, so without
   this the image is flush against the date line above and the article below.

   max-width puts the photograph on the same measure as the article under it.
   The width used to come from the sizes attribute instead: with w descriptors
   an image lays out at its sizes width, and those attributes still said 68ch
   after --measure went to 72ch, so the photograph sat about 35px narrower than
   its own text. Issue #11 called that "neither on the text measure nor
   deliberately full bleed". The decision is the measure, and it lives here in
   CSS so the two cannot drift apart again: sizes is now only a hint about which
   file to fetch. */
.post__figure {
  margin-block: var(--s-5);
  max-width: var(--measure);
}

/* The photographer's credit sits with the photograph it belongs to, rather
   than as the last paragraph of the article where it read as body copy. */
.post__figure figcaption {
  margin-block-start: var(--s-2);
  font-size: var(--t-sm);
  color: var(--c-ink-muted);
}

.post__figure figcaption a {
  color: var(--c-link);
}

/* --- tags ----------------------------------------------------------------- */

/* Colour is never the only carrier of meaning: every tag has a text label. */
/* Bold, because the warm pair sets the orange at 13px and it read thin, and
   because warm and cool tags share a row on /news/ and the homepage: lifting
   only the orange ones would put two weights side by side. 6.06:1 warm on the
   ink chip, 10.88:1 cool on the pale one. */
.tag {
  display: inline-block;
  padding: var(--s-1) var(--s-3);
  border-radius: var(--radius-pill);
  font-size: var(--t-xs);
  font-weight: var(--fw-bold);
  background: var(--c-surface-alt);
  color: var(--c-ink);
  white-space: nowrap;
}

.tag--announcement { background: var(--c-tag-warm-bg); color: var(--c-tag-event); }
.tag--press        { background: var(--c-tag-warm-bg); color: var(--c-tag-publication); }
.tag--milestone    { background: var(--c-tag-cool-bg); color: var(--c-tag-milestone); }
.tag--research     { background: var(--c-tag-cool-bg); color: var(--c-tag-research); }
.tag--event        { background: var(--c-tag-warm-bg); color: var(--c-tag-event); }

/* --- cards ---------------------------------------------------------------- */

.card {
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: var(--s-5);
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  position: relative;
}

/* Design SIG: "exaggerate hover effect on cards" and "hover not light blue,
   make it darker orange". The lift is bigger than before and the edge picks up
   the accent, so the feedback is unmistakable without changing the card's own
   neutral surface. transform is fine here: .card is not a layout container, and
   the reduced-motion block in tokens.css already kills the transition. */
.card {
  transition: box-shadow 150ms ease-out, transform 150ms ease-out, border-color 150ms ease-out;
}

.card:has(.card__link:hover),
.card:has(.card__link:focus-visible) {
  box-shadow: var(--shadow-raised);
  /* 2.33:1 against the page. It is hover feedback alongside a lift and a
     shadow, not the only way to identify the card, so the boundary rule does
     not bite; the brand orange is the point of it. */
  border-color: var(--c-brand-orange);
  transform: translateY(-3px);
}

/* The whole card is the click target, and the accessible name is the title, 
   not four identical "Read more" links, which is what the draft had. */
.card__link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.card__link {
  color: inherit;
  text-decoration: none;
}

.card__link:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Card headings. Previously these borrowed .brand__name, which is the site
   header's wordmark, so editing the header restyled every partner card. */
.card__title {
  font-size: var(--t-lg);
  line-height: var(--lh-snug);
}

/* An aside inside an article, such as the deliverable a news item relates to. */
.card--note {
  margin-block-start: var(--s-6);
  max-width: var(--measure);
}

.card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
  font-size: var(--t-sm);
  color: var(--c-ink-muted);
}

.card__media {
  /* display:block explicitly: the team page uses a <span> for this, and an
     inline box ignores aspect-ratio and overflow. */
  display: block;
  margin: calc(var(--s-5) * -1) calc(var(--s-5) * -1) 0;
  border-radius: var(--radius) var(--radius) 0 0;
  overflow: hidden;
  background: var(--c-surface-alt);
  aspect-ratio: 16 / 9;
}

/* Head shots. 16/9 crops a face to a letterbox strip, and 4/3 is not much
   kinder: the uploaded portraits are taller than they are wide (252 by 372 for
   the first one), so any landscape frame cuts the top and bottom off a head.
   Square fills the card width, as Design SIG asked, without decapitating anyone,
   and copes with both portrait and landscape originals. */

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- team ----------------------------------------------------------------- */

/* The portrait: a circle centred at the top of the card.

   One custom property drives it, so the size is tuned in one place. 9rem is
   deliberate rather than arbitrary: the seven uploaded photographs are between
   136px and 552px wide, so 144px is at or below source size for five of them.
   The 288px square this replaced upscaled nearly all of them. */
.card--person {
  --person-photo-size: 9rem;
}

/* The image transform wraps every <img> in a <picture>. Left alone that
   wrapper becomes the flex item in the dialog head and the layout box in the
   card, so the sizing and centring below would apply to the image inside a box
   that does not match it. display:contents removes the wrapper's own box and
   lets the image be the child it looks like. */
.card--person picture,
.person-dialog__head picture {
  display: contents;
}

.person__photo {
  width: var(--person-photo-size);
  height: var(--person-photo-size);
  /* The card is a flex column, so auto margins are what centre a single item
     on the cross axis. */
  margin-inline: auto;
  border-radius: 50%;
  object-fit: cover;
  background: var(--c-surface-alt);
  /* The uploads are portrait, so pull the crop up towards the face rather than
     taking the middle of the frame, which lands on the chin. */
  object-position: 50% 25%;
  aspect-ratio: 1;
  flex: none;
}

/* A member whose photograph we do not have yet. Same tint, border and accent
   text as .partner-card__logo--empty, which is the placeholder plate on a
   partner with no logo, so the two placeholders are visibly the same decision.
   Four of the eleven are in this state. */
.person__photo--empty {
  display: grid;
  place-items: center;
  background: var(--c-surface-alt);
  border: 1px solid var(--c-border);
  font-size: var(--t-2xl);
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  color: var(--c-ink-muted);
}

/* Centring is scoped to the person card. .card is shared with news, partners
   and deliverables, all of which stay left aligned. */
.card--person {
  text-align: center;
}

/* The card's trigger is a button, so it needs the browser's button styling
   taken off before .card__title's own styling shows through. */
.card--person .card__link {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  text-align: inherit;
  cursor: pointer;
}

/* Tells people the card does something. aria-hidden in the markup, because the
   button's own accessible name already says what activating it does, and a
   screen reader should not hear "Read biography" twice per card. */
.person__cue {
  font-size: var(--t-sm);
  color: var(--c-link);
  font-weight: var(--fw-medium);
  margin-block-start: auto;
  text-decoration: underline;
  text-decoration-color: var(--c-link-rule);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

/* --- the biography overlay ------------------------------------------------ */

/* popover="auto", so the browser gives Escape, click-outside, focus return and
   the guarantee that opening one closes any other. That last part is Yao's
   "one person's biography at a time", enforced rather than hoped for, and it
   costs no JavaScript.

   The UA stylesheet already sets position:fixed, margin:auto and display:none
   when closed, so only the appearance is set here. */
.person-dialog {
  width: min(34rem, calc(100vw - 2 * var(--gutter)));
  max-height: calc(100dvh - 2 * var(--s-6));
  overflow: auto;
  padding: var(--s-6);
  background: var(--c-surface);
  color: var(--c-ink);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-raised);
}

.person-dialog::backdrop {
  background: var(--c-scrim);
}

/* @starting-style is what gives it a state to animate from. transition-behavior
   carries display and overlay, which are discrete properties, so the box stays
   in the top layer for the length of the fade instead of vanishing on frame
   one. The reduced-motion block in tokens.css neutralises all of it. */
@media (prefers-reduced-motion: no-preference) {
  .person-dialog,
  .person-dialog::backdrop {
    transition:
      opacity 180ms ease-out,
      transform 180ms ease-out,
      display 180ms allow-discrete,
      overlay 180ms allow-discrete;
    opacity: 0;
  }

  .person-dialog {
    transform: translateY(0.75rem) scale(0.98);
  }

  .person-dialog:popover-open,
  .person-dialog:popover-open::backdrop {
    opacity: 1;
  }

  .person-dialog:popover-open {
    transform: none;
  }

  @starting-style {
    .person-dialog:popover-open,
    .person-dialog:popover-open::backdrop {
      opacity: 0;
    }
    .person-dialog:popover-open {
      transform: translateY(0.75rem) scale(0.98);
    }
  }
}

.person-dialog__close {
  float: inline-end;
  /* 44px, so it is a comfortable target on a phone rather than a 16px glyph. */
  min-width: 44px;
  min-height: 44px;
  font-size: var(--t-xl);
  line-height: 1;
  color: var(--c-ink-muted);
  background: none;
  border: 0;
  cursor: pointer;
}

.person-dialog__close:hover {
  color: var(--c-ink);
}

.person-dialog__head {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-block-end: var(--s-5);
}

/* A smaller circle than the card's, and left aligned: there is a block of text
   beside it here rather than under it. */
.person-dialog__head .person__photo {
  --person-photo-size: 7rem;
  margin-inline: 0;
}

.person-dialog__name {
  font-size: var(--t-xl);
  line-height: var(--lh-snug);
}

.person-dialog__org {
  font-size: var(--t-sm);
  color: var(--c-ink-muted);
}

.person-dialog .person__links {
  margin-block-start: var(--s-5);
}

/* The overlay is prose, so it is left aligned even though the card it sits
   inside is centred. Centred paragraphs are harder to read. */
.person-dialog {
  text-align: left;
}

.person__bio-body > * + * {
  margin-block-start: var(--s-3);
}

.person__role {
  color: var(--c-ink-muted);
  font-size: var(--t-sm);
  font-weight: var(--fw-medium);
}

/* The biography body, inside the overlay. 11 people with their bios on the page
   at once made it a wall of text, which is what Yao raised. */
.person__bio-body {
  font-size: var(--t-sm);
}

.person__links {
  display: flex;
  gap: var(--s-3);
  font-size: var(--t-sm);
  /* A real length, not `auto`. auto only resolves against a flex or grid
     parent, and .person-dialog is a plain block, so it computed to zero and
     these links sat on the last line of the biography. It reads as a margin
     that is present and does nothing, which is why it survived review. */
  margin-block-start: var(--s-5);
}

.institution-group + .institution-group {
  margin-block-start: var(--s-7);
}

.institution-group > h2 {
  font-size: var(--t-xl);
  color: var(--c-ink);
  padding-block-end: var(--s-3);
  border-block-end: 1px solid var(--c-border);
  margin-block-end: var(--s-5);
}

/* --- partners ------------------------------------------------------------- */

/* Centred, and every card the same height regardless of what its logo is
   shaped like. These range from 3.5:1 (Newcastle) to 11.2:1 (the UCL banner),
   so a min-height left them sitting at different heights down the row. */
.partner-card {
  align-items: center;
  text-align: center;
}

.partner-card__logo {
  display: grid;
  place-items: center;
  width: 100%;
  height: 72px;
  padding: var(--s-3);
  /* White by default. A partner whose only published logo is the reversed
     (white) version sets logo_background to their own brand colour, because
     that is where a reversed logo is meant to sit and recolouring someone
     else's artwork is not ours to do. */
  background: var(--partner-logo-bg, #ffffff);
  border-radius: var(--radius);
}

/* Fit inside the box on whichever axis binds first: height for a squarer logo,
   width for a wide banner. Without the max-width a wide one overflows; without
   height:auto the aspect distorts once max-width clamps it. */
.partner-card__logo img {
  max-height: var(--logo-max-h);
  max-width: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* A partner whose logo we do not have yet. White on the near-white card was
   1.02:1, so the plate was invisible and the acronym looked like a stray label
   floating in dead space. Tinted and outlined, it reads as a deliberate
   placeholder. Eleven of the seventeen are in this state. */
.partner-card__logo--empty {
  background: var(--c-surface-alt);
  border: 1px solid var(--c-border);
}

/* Its own class rather than borrowing .partner-card__country, which is the
   muted 15px caption underneath and made the acronym look incidental.
   Accent on the tinted plate measures 6.08:1. */
.partner-card__acronym {
  font-size: var(--t-xl);
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  color: var(--c-ink);
}

.partner-card__country {
  font-size: var(--t-sm);
  color: var(--c-ink-muted);
}

/* The parts of a beneficiary the project actually works in, named under the
   legal entity that signed. Newcastle City Council is the beneficiary; the work
   happens at the Great North Museum and in the city libraries, and the
   coordinator asked for both to be visible.

   Smaller and lighter than the country line above it, because it qualifies the
   partner rather than identifying it, and the card is already a short column.
   13px would fail 1.4.3, so this stays at --t-sm and separates itself with the
   rule above instead. */
.partner-card__departments {
  margin-block-start: var(--s-2);
  padding-block-start: var(--s-2);
  border-block-start: 1px solid var(--c-border);
  font-size: var(--t-sm);
  color: var(--c-ink-muted);
}

/* --- page banner ---------------------------------------------------------- */

/* The deep blue, behind every page title, and the same value the project facts
   strip takes on the home page: one blue band on the site rather than two. The
   home page does not take this rule, because its full width block at the top is
   the photographic hero.

   :has(h1) is what separates a page title from the section headings further
   down the page; every layout and page template puts exactly one h1 in a
   .section-heading, verified across the built output.

   This replaces --c-brand-blue, #0d75ff, and the change is mostly a release
   rather than a restyle. White on #0d75ff is 4.20:1: over the 3 WCAG 1.4.3
   asks of large text, under the 4.5 body text needs. So everything in the band
   had to be large to be legal, which is why the lede was 1.5rem and the eyebrow
   20px bold, and why a privacy page opened with an intro set larger than its
   own policy. White on --c-ink is 14.15:1 and constrains nothing at any size.

   A page's one-line lede sits in the band under its h1, so the title and what
   the page is for read as one block. White on --c-ink
   has no size constraint, so the lede keeps its normal size. A news post's
   metadata, back link and photograph stay below the band. */
.section-heading:has(h1) {
  background: var(--c-ink);
  color: var(--c-focus-light);
  /* Full bleed out of .container without touching a single template. */
  margin-inline: calc(50% - 50vw);
  padding-inline: calc(50vw - 50%);
  /* Pulls up into the space .section leaves above it, so the band meets the
     header instead of floating. */
  margin-block-start: calc(var(--s-8) * -1);
  /* --s-7, not --s-8. With only the h1 left in here, 64px of padding each side
     made a 250px slab for one line of text, which is what opened 19 of 22
     pages identically. 48px each side puts it at about 142px. */
  padding-block: var(--s-7);
  /* Short, because what follows is now the lede that belongs to this title. */
  margin-block-end: var(--s-5);
}

/* Re-bound on the children, never on the band itself. A custom property
   declared on an element also applies to that element's own declarations, so
   `--c-ink: var(--c-focus-light)` beside `background: var(--c-ink)` would paint
   the band white and then write white on it. That is the exact bug
   check-css-tokens.mjs was written for, after the facts strip shipped it.

   Both the inherited `color` above and these re-binds are needed: setting only
   the selectors is what let .card__meta through CI at 3.02:1. .tag is left
   alone, since its own --c-tag-* colours on its light chip are correct here. */
.section-heading:has(h1) > * {
  --c-ink: var(--c-focus-light);
  --c-ink-muted: var(--c-focus-light);
  --c-link: var(--c-focus-light);
  --c-link-rule: currentColor;
  --c-focus: var(--c-focus-light);
}

/* The things that used to live inside the band and now sit under it. They
   carry the gap the band used to.

   `~` and not `+`, because the order differs by layout: a news post leads with
   the back link, then the lede, then the date; a work package leads with the
   back link, then the lead and dates, then the summary; /about/ has no back
   link at all. An adjacency rule only ever fitted whichever layout it was
   written against, and silently dropped the spacing on the others the moment
   anything moved. The selector is scoped to the siblings of a page band, so a
   .lede nested inside a section further down is untouched. */
.section-heading:has(h1) ~ .back-link,
.section-heading:has(h1) ~ .card__meta {
  margin-block-end: var(--s-4);
}

.section-heading:has(h1) ~ .lede {
  margin-block-end: var(--s-6);
}

/* The way back out of an article. Smaller than the body, because it is an
   affordance rather than content. */
.back-link {
  font-size: var(--t-sm);
}

.section-heading:has(h1) .eyebrow {
  /* Back to 13px, the size every other eyebrow is. It was 20px bold only to
     clear the 18.7px bold threshold on #0d75ff; on --c-ink it is 14.15:1. */
  color: var(--c-focus-light);
}

.section-heading:has(h1) h1 {
  color: var(--c-focus-light);
}

.section-heading:has(h1) a {
  color: var(--c-focus-light);
}

/* --- small print ---------------------------------------------------------- */

/* Secondary text next to a value: a deliverable summary, a project month, a
   "not public" note. The deliverables table borrowed .partner-card__country for
   all of these, which coupled it to a component it has nothing to do with. */
.meta-note {
  font-size: var(--t-sm);
  color: var(--c-ink-muted);
}

/* --- work packages -------------------------------------------------------- */

.wp-card__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
}

.wp-card__status {
  margin-inline-start: auto;
  font-size: var(--t-xs);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--c-ink-muted);
}

.objectives {
  margin: 0;
  padding-inline-start: var(--s-5);
  /* Full sentences, so they take the reading measure like any other prose. The
     deliverable table below them does not: seven columns need the room. */
  max-width: var(--measure);
  color: var(--c-ink-muted);
}

.objectives li + li {
  margin-block-start: var(--s-2);
}

/* --- deliverables table --------------------------------------------------- */

.table-scroll {
  overflow-x: auto;
}

/* `separate` rather than `collapse`, because border-radius is ignored under
   collapse: the table's corners were square while every card beside it was
   rounded. border-spacing: 0 keeps the cells flush, so nothing else changes,
   and the caption stays outside the border where it already sat. */
.table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
}

.table caption {
  text-align: left;
  padding-block-end: var(--s-3);
  color: var(--c-ink-muted);
  font-size: var(--t-sm);
}

.table th,
.table td {
  text-align: left;
  padding: var(--s-3) var(--s-4);
  border-block-end: 1px solid var(--c-border);
  vertical-align: top;
}

.table th {
  font-size: var(--t-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-ink-muted);
  white-space: nowrap;
}

.table tbody tr:last-child td {
  border-block-end: none;
}

.status {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--t-sm);
  white-space: nowrap;
}

.status::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}

.status--planned     { color: var(--c-status-planned); }
.status--in-progress { color: var(--c-status-progress); }
.status--submitted   { color: var(--c-status-submitted); }
.status--approved    { color: var(--c-status-approved); }

/* --- empty states --------------------------------------------------------- */

.empty {
  padding: var(--s-6);
  border: 1px dashed var(--c-border);
  border-radius: var(--radius);
  color: var(--c-ink-muted);
  text-align: center;
}
