/* ==========================================================================
   Content types
   --------------------------------------------------------------------------
   The baseline for the things a case study is made of beyond prose: figures,
   stat blocks, pull quotes. Shared by both themes.

   This file holds structure and the least opinionated treatment that still
   reads correctly. Everything characterful lives in the token layer, which is
   the only thing that differs between the two themes.
   Semantic and component tokens only.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Figure
   -------------------------------------------------------------------------- */

.figure {
  margin-block: var(--space-stack-xl);
  margin-inline: var(--space-none);
}

.figure__media {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-media);
  /* Its own surface, not the figure panel's. A theme that fills the figure
     needs the media to sit on something else or the two dissolve into each
     other; a theme that does not can point this at the same surface. */
  background-color: var(--figure-media-surface);
}

.figure__caption {
  margin-block-start: var(--space-stack-sm);
  max-width: var(--measure-narrow);
  font-family: var(--type-caption-font);
  font-size: var(--type-caption-size);
  font-weight: var(--type-caption-weight);
  line-height: var(--type-caption-leading);
  letter-spacing: var(--type-caption-tracking);
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Stats
   --------------------------------------------------------------------------
   A description list, because that is what it is: each number is a value and
   each label is its term. Value before label in the source, reversed visually
   with flex ordering so the number reads first without lying about structure.
   -------------------------------------------------------------------------- */

.stats {
  margin-block: var(--space-stack-xl);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-stack-lg);
}

/* No min-width: 0. A stat cell is never allowed to be narrower than its value;
   layout.css wraps it to its own row instead. */
.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-stack-2xs);
}

.stat__value {
  font-family: var(--type-metric-font);
  font-size: var(--type-metric-size);
  font-weight: var(--type-metric-weight);
  line-height: var(--type-metric-leading);
  letter-spacing: var(--type-metric-tracking);
  color: var(--text-primary);
}

.stat__label {
  margin-inline-start: var(--space-none);
  font-family: var(--type-metric-label-font);
  font-size: var(--type-metric-label-size);
  font-weight: var(--type-metric-label-weight);
  line-height: var(--type-metric-label-leading);
  letter-spacing: var(--type-metric-label-tracking);
  text-transform: var(--type-metric-label-transform);
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Entry list
   --------------------------------------------------------------------------
   A list of things, each with a title, an optional line of context and a
   sentence or two. The Work index and the About links are both this.

   Some titles are links and some are not, and a visitor has to be able to
   tell which at a glance. So the difference is the one the web already uses:
   a linked title is in the link colour and underlined, an unlinked one is set
   exactly like body text. Not greyed out, because a muted title reads as a
   disabled control, and not link-coloured, because a link-coloured title that
   goes nowhere reads as a broken link. The underline means colour is never
   the only thing carrying the difference.
   -------------------------------------------------------------------------- */

.entry {
  display: flex;
  flex-direction: column;
  gap: var(--space-stack-2xs);
  min-width: 0;
}

.entry__title {
  font-family: var(--type-subheading-font);
  font-size: var(--type-subheading-size);
  font-weight: var(--type-subheading-weight);
  line-height: var(--type-subheading-leading);
  letter-spacing: var(--type-subheading-tracking);
  text-transform: var(--type-subheading-transform);
  color: var(--text-primary);
}

.entry__link {
  color: var(--text-link);
  text-decoration: underline;
  text-underline-offset: var(--space-inline-2xs);
}

.entry__link:hover { color: var(--text-link-hover); }

.entry__meta {
  font-family: var(--type-label-font);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-leading);
  letter-spacing: var(--type-label-tracking);
  text-transform: var(--type-label-transform);
  color: var(--text-muted);
}

.entry__summary {
  max-width: var(--measure-prose);
  font-family: var(--type-body-font);
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-leading);
  letter-spacing: var(--type-body-tracking);
  color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   Quote
   --------------------------------------------------------------------------
   Someone else's words, with who said them. A figure, because the quote and
   its attribution belong together: the blockquote holds one or more
   paragraphs, the figcaption holds the name and then the title. Anonymous
   quotes use the same component with no figcaption at all, rather than an
   empty one, so there is nothing for a screen reader to announce.

   The text is set exactly as the source has it, quotation marks and mixed
   straight and curly apostrophes included, because the words are not ours
   to tidy. For the same reason the title is not given a text-transform: a
   person's job title appears as they wrote it.

   A run of these is an .entry-list, not a new list. That gives each theme
   its existing answer for a list of things, ruled rows or raised cards, and
   the rhythm between quotes comes from the entry tokens rather than from
   anything set here.

   The figcaption is laid out as a row with one item today, the name and title
   stacked in .quote__who. A headshot goes in front of .quote__who as a second
   item, and the row's gap already spaces it. No markup has to change shape.
   -------------------------------------------------------------------------- */

.quote {
  display: flex;
  flex-direction: column;
  gap: var(--space-stack-sm);
  min-width: 0;
}

.quote__text {
  max-width: var(--measure-prose);
  font-family: var(--type-body-lg-font);
  font-size: var(--type-body-lg-size);
  font-weight: var(--type-body-lg-weight);
  line-height: var(--type-body-lg-leading);
  letter-spacing: var(--type-body-lg-tracking);
  color: var(--text-primary);
}

/* A quote split across paragraphs in the source keeps the split. */
.quote__text > * + * {
  margin-block-start: var(--space-prose-paragraph);
}

.quote__attribution {
  display: flex;
  align-items: center;
  gap: var(--space-inline-sm);
}

.quote__who {
  display: flex;
  flex-direction: column;
  gap: var(--space-stack-2xs);
  min-width: 0;
}

.quote__name {
  font-family: var(--type-ui-font);
  font-size: var(--type-ui-size);
  font-weight: var(--type-ui-weight);
  line-height: var(--type-ui-leading);
  letter-spacing: var(--type-ui-tracking);
  color: var(--text-primary);
}

.quote__title {
  font-family: var(--type-body-sm-font);
  font-size: var(--type-body-sm-size);
  font-weight: var(--type-body-sm-weight);
  line-height: var(--type-body-sm-leading);
  letter-spacing: var(--type-body-sm-tracking);
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Rating chart
   --------------------------------------------------------------------------
   A horizontal bar chart that is a table. The caption names the series, each
   row header is a rating as the survey worded it, and each data cell holds the
   percentage as text with a bar beneath it. Assistive technology reads the
   table; the bar is an empty span and says nothing.

   One series, so one hue: every bar is the accent, never coloured by rank,
   and the caption does the job a legend would. Every piece of text wears a
   text token, never the fill.

   The length is data, not design. The row carries it inline as --pct, and the
   bar is that share of its track. A zero row has no bar at all, only its 0%
   and the empty track, so nothing reads as a sliver of a vote.

   The percentage sits above the bar rather than at its end, so every track
   starts and ends in the same place whatever the number, and no room has to be
   held back beside the longest bar for its label. Labels wrap at phone widths
   and stay on one line from 48rem, where there is room for them.

   Nothing here is interactive, so nothing has a hover state.
   -------------------------------------------------------------------------- */

.rating-charts {
  display: grid;
  gap: var(--space-stack-lg);
  margin-block-start: var(--space-prose-paragraph);
  max-width: var(--measure-prose);
}

.rating-chart {
  inline-size: 100%;
  border-collapse: collapse;
}

.rating-chart__caption {
  margin-block-end: var(--space-stack-xs);
  text-align: start;
  font-family: var(--type-subheading-font);
  font-size: var(--type-subheading-size);
  font-weight: var(--type-subheading-weight);
  line-height: var(--type-subheading-leading);
  letter-spacing: var(--type-subheading-tracking);
  text-transform: var(--type-subheading-transform);
  color: var(--text-primary);
}

.rating-chart__label {
  padding-block: var(--space-stack-xs);
  padding-inline: var(--space-none) var(--space-inline-sm);
  vertical-align: top;
  text-align: start;
  font-family: var(--type-body-sm-font);
  font-size: var(--type-body-sm-size);
  font-weight: var(--type-body-sm-weight);
  line-height: var(--type-body-sm-leading);
  letter-spacing: var(--type-body-sm-tracking);
  color: var(--text-secondary);
}

/* The data column takes whatever width the labels leave, so the bars get it. */
.rating-chart__datum {
  inline-size: 100%;
  padding-block: var(--space-stack-xs);
  padding-inline: var(--space-none);
  vertical-align: top;
}

.rating-chart__value {
  display: block;
  margin-block-end: var(--space-stack-2xs);
  font-family: var(--type-body-sm-font);
  font-size: var(--type-body-sm-size);
  font-weight: var(--type-body-sm-weight);
  line-height: var(--type-body-sm-leading);
  letter-spacing: var(--type-body-sm-tracking);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

.rating-chart__track {
  display: block;
  block-size: var(--space-stack-sm);
  background-color: var(--surface-subtle);
  border-start-end-radius: var(--radius-control);
  border-end-end-radius: var(--radius-control);
}

.rating-chart__bar {
  display: block;
  inline-size: var(--pct);
  block-size: 100%;
  background-color: var(--surface-accent);
  border-start-end-radius: var(--radius-control);
  border-end-end-radius: var(--radius-control);
}

@media (min-width: 48rem) {
  .rating-chart__label {
    white-space: nowrap;
  }
}

/* Forced colours paint every background as Canvas, which would take the bars
   with it. An edge in --border-accent, which the token files point at
   CanvasText in this mode, keeps each bar's length visible. */
@media (forced-colors: active) {
  .rating-chart__bar {
    border: var(--border-width-strong) solid var(--border-accent);
  }
}

/* --------------------------------------------------------------------------
   Pull quote
   -------------------------------------------------------------------------- */

.pullquote {
  margin-block: var(--space-stack-xl);
  margin-inline: var(--space-none);
}

.pullquote p {
  margin: var(--space-none);
  max-width: var(--measure-display);
  font-family: var(--type-quote-font);
  font-size: var(--type-quote-size);
  font-weight: var(--type-quote-weight);
  font-style: var(--type-quote-style);
  line-height: var(--type-quote-leading);
  letter-spacing: var(--type-quote-tracking);
  color: var(--text-primary);
}

.pullquote__attribution {
  display: block;
  margin-block-start: var(--space-stack-sm);
  font-family: var(--type-label-font);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-leading);
  letter-spacing: var(--type-label-tracking);
  text-transform: var(--type-label-transform);
  font-style: normal;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Breakout
   --------------------------------------------------------------------------
   Lets a figure escape the prose measure without leaving the article. The
   article is a grid with a single named column; a breakout child spans wider
   named lines. Each direction decides how far.
   -------------------------------------------------------------------------- */

.breakout {
  width: 100%;
  max-width: var(--layout-wide-max);
}

/* --------------------------------------------------------------------------
   <picture> is a selection wrapper, not a box. Taking it out of the box tree
   lets the <img> inside participate directly in whatever layout its parent
   sets up, so a pane or a figure does not have to know it is there.
   -------------------------------------------------------------------------- */

picture {
  display: contents;
}

/* --------------------------------------------------------------------------
   A figure holding a list of images side by side.
   -------------------------------------------------------------------------- */

.figure__panes {
  display: grid;
  gap: var(--space-stack-md);
}

@media (min-width: 48rem) {
  .figure__panes {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-inline-md);
  }
}

.figure__pane {
  margin: var(--space-none);
  min-width: 0;
}

.figure__pane-label {
  display: block;
  margin-block-end: var(--space-stack-2xs);
  font-family: var(--type-label-font);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-leading);
  letter-spacing: var(--type-label-tracking);
  text-transform: var(--type-label-transform);
  color: var(--text-muted);
}

/* A set that stays stacked at every width. For images whose rows line up
   vertically, reading down one column beats reading across several. */
.figure__panes--stacked {
  grid-template-columns: 1fr;
}

@media (min-width: 48rem) {
  .figure__panes--stacked {
    grid-template-columns: 1fr;
    gap: var(--space-stack-md);
  }
}

/* --------------------------------------------------------------------------
   Resume
   --------------------------------------------------------------------------
   The resume is built from what the case studies already use: its sections
   are .section, its headings .section__title, its prose .section__body. What
   is here is only what a resume has and a case study does not: a contact
   block and portrait, employers with dates, roles, bullets, and a sidebar of
   short lists. The two-column split is layout and lives in layout.css.

   The contact icons are Material Symbols ligatures. They take the size of
   the text beside them rather than the icon font's own 24px, and they are
   aria-hidden in the markup, so a screen reader reads the address and not
   the word "mail" in front of it.
   -------------------------------------------------------------------------- */

.resume { padding-block-end: var(--space-section); }

.resume__tagline {
  margin-block-start: var(--space-stack-md);
  font-family: var(--type-lede-font);
  font-size: var(--type-lede-size);
  font-weight: var(--type-lede-weight);
  line-height: var(--type-lede-leading);
  letter-spacing: var(--type-lede-tracking);
  color: var(--text-secondary);
  text-wrap: balance;
}

.resume__summary {
  margin-block-start: var(--space-stack-md);
  max-width: var(--measure-prose);
  font-family: var(--type-body-font);
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-leading);
  letter-spacing: var(--type-body-tracking);
  color: var(--text-secondary);
}

.resume__aside {
  display: grid;
  gap: var(--space-stack-lg);
  justify-items: start;
}

.resume__contact li {
  font-family: var(--type-body-sm-font);
  font-size: var(--type-body-sm-size);
  font-weight: var(--type-body-sm-weight);
  line-height: var(--type-body-sm-leading);
  letter-spacing: var(--type-body-sm-tracking);
  color: var(--text-secondary);
  overflow-wrap: anywhere;
}

.resume__contact li + li {
  margin-block-start: var(--space-stack-xs);
}

.resume__contact .material-symbols-outlined {
  font-size: inherit;
  vertical-align: middle;
  color: var(--text-muted);
}

.resume__contact a {
  color: var(--text-link);
  text-decoration: underline;
  text-underline-offset: var(--space-inline-2xs);
}

.resume__contact a:hover { color: var(--text-link-hover); }

.resume__portrait {
  inline-size: 100%;
  max-inline-size: var(--media-portrait-size);
  block-size: auto;
  border-radius: var(--radius-pill);
  background-color: var(--surface-subtle);
}

/* One employer. Wider apart than paragraphs, because each is its own block
   of roles. Outranks .section__body > * + * on purpose. */
.section__body > .resume__entry + .resume__entry {
  margin-block-start: var(--space-stack-xl);
}

.resume__entry > * + * {
  margin-block-start: var(--space-stack-xs);
}

.resume__company-time {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  column-gap: var(--space-inline-md);
  row-gap: var(--space-stack-2xs);
}

.resume__company {
  font-family: var(--type-subheading-font);
  font-size: var(--type-subheading-size);
  font-weight: var(--type-subheading-weight);
  line-height: var(--type-subheading-leading);
  letter-spacing: var(--type-subheading-tracking);
  text-transform: var(--type-subheading-transform);
  color: var(--text-primary);
}

.resume__timeframe {
  margin: var(--space-none);
  font-family: var(--type-label-font);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-leading);
  letter-spacing: var(--type-label-tracking);
  text-transform: var(--type-label-transform);
  color: var(--text-muted);
}

.resume__entry > .resume__roles {
  margin-block-start: var(--space-stack-md);
}

.resume__role {
  font-family: var(--type-ui-font);
  font-size: var(--type-ui-size);
  font-weight: var(--type-ui-weight);
  line-height: var(--type-ui-leading);
  letter-spacing: var(--type-ui-tracking);
  color: var(--text-primary);
}

.resume__roles dd {
  margin-block-start: var(--space-stack-xs);
}

.resume__bullets {
  list-style: disc;
  padding-inline-start: var(--space-inline-lg);
}

.resume__bullets li {
  max-width: var(--measure-prose);
  font-family: var(--type-body-font);
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-leading);
  letter-spacing: var(--type-body-tracking);
  color: var(--text-secondary);
}

.resume__bullets li + li {
  margin-block-start: var(--space-stack-xs);
}

.resume__bullets li::marker { color: var(--text-muted); }

.resume__list + .resume__list {
  margin-block-start: var(--space-stack-md);
}

.resume__list dt {
  font-family: var(--type-ui-font);
  font-size: var(--type-ui-size);
  font-weight: var(--type-ui-weight);
  line-height: var(--type-ui-leading);
  letter-spacing: var(--type-ui-tracking);
  color: var(--text-primary);
}

.resume__list dd {
  margin-block-start: var(--space-stack-2xs);
  font-family: var(--type-body-sm-font);
  font-size: var(--type-body-sm-size);
  font-weight: var(--type-body-sm-weight);
  line-height: var(--type-body-sm-leading);
  letter-spacing: var(--type-body-sm-tracking);
  color: var(--text-secondary);
}
