/*
  cpp-grail components
  ====================

  Theme-agnostic. Every rule consumes the `--g-*` contract declared by whichever theme
  is active (see website/themes/) and never names a color or a typeface directly, so
  adding an identity means adding one theme file -- not editing this one.

  Rules are prefixed with `:root` purely for specificity: it matches unconditionally and
  carries the same weight as the attribute selector it replaced, so these overrides still
  beat Material's defaults whether or not a theme attribute has been set.
*/

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

:root .md-typeset {
  font-family: var(--g-font-body);
  font-size: var(--g-body-size);
  line-height: var(--g-line-height);
}

:root .md-typeset h1,
:root .md-typeset h2,
:root .md-typeset h3,
:root .md-typeset h4 {
  color: var(--g-fg);
  font-family: var(--g-font-display);
  font-weight: var(--g-display-weight);
  letter-spacing: var(--g-display-tracking);
}

:root .md-typeset h1 {
  font-size: calc(var(--g-h1-size) * var(--g-display-scale));
  line-height: 1.15;
  text-wrap: balance;
  margin: 0 0 var(--g-gap);
  text-transform: var(--g-display-transform);
}

:root .md-typeset h2 {
  border-bottom: var(--g-rule-width) solid var(--g-border);
  text-wrap: balance;
  font-size: var(--g-text-xl);
  margin-top: 2.6rem;
  padding-bottom: 0.35rem;
}

:root .md-typeset h3 {
  font-size: var(--g-text-lg);
  margin-top: 1.9rem;
}

:root .md-typeset code {
  background: var(--g-surface-alt);
  border-radius: var(--g-radius);
  color: var(--g-fg);
  font-family: var(--g-font-mono);
  font-size: 0.86em;
  padding: 0.1em 0.35em;
}

:root .md-typeset a {
  color: var(--g-accent-text);
  /* The underline used to be drawn in the border grey, which on a coloured link reads
     as a rendering fault rather than a decoration. It is the link's own colour, held
     back so it sits under the word instead of competing with it. */
  text-decoration-color: currentcolor;
  text-decoration-color: color-mix(in srgb, currentcolor 45%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

:root .md-typeset a:hover,
:root .md-typeset a:focus-visible {
  color: var(--g-accent-strong);
  text-decoration-color: currentcolor;
}

:root .md-content__inner {
  margin-inline: auto;
  max-width: var(--g-content-width);
  padding-bottom: 3rem;
  /* The gutter is padding rather than margin. Material supplies it as a horizontal
     margin, which centring the column would otherwise cancel -- leaving text flush
     against both edges of a phone screen. */
  padding-inline: 0.8rem;
}

/* Material bleeds top-level code blocks past that gutter on small screens, which
   assumed the margin we just replaced. Ours are bordered blocks, so keep them inside
   the column; left as-is they hang 0.8rem off each edge and scroll the page. */
:root .md-content__inner > pre,
:root .md-content__inner > .highlight {
  margin-inline: 0;
}

/* Prose is held to a comfortable measure while the column stays wide enough for code.
   Capping the text rather than the container is what lets both be right at once.

   Only unclassed lists: a list we lay out ourselves -- the card grids, the stat row --
   is a component with its own width, and capping it to a reading measure leaves it
   short of the column it sits in. */
:root .md-typeset > p,
:root .md-typeset > ul:not([class]),
:root .md-typeset > ol:not([class]),
:root .md-typeset > blockquote,
:root .md-typeset > .entry-predict,
:root .md-typeset > .entry-takeaway {
  max-width: var(--g-measure);
}

/* Code keeps the line breaks it was written with. Wrapping restarts the continuation
   at column zero, which on a page made of C++ reads as a second statement -- the fix
   for a long line is a column wide enough to hold it, not a soft break in the middle
   of an expression. The column set in base.css holds the longest line in the
   repository, so the scrollbar below is a backstop rather than a normal state.

   The scroll is on the <code>, so the block's border and background stay put and only
   the text moves; `overscroll-behavior-inline` stops a trackpad flick inside a snippet
   from turning into a page swipe. */
:root .md-typeset pre > code {
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  white-space: pre;
}

/* A wide table scrolls inside its own wrapper rather than moving the page. Cells
   prefer to wrap, so the scrollbar only appears when the content genuinely cannot fit. */
:root .md-typeset table:not([class]) td,
:root .md-typeset table:not([class]) th {
  overflow-wrap: break-word;
}

/* ------------------------------------------------------------------- chrome */

/* At the top of a page the header and the tab strip read as one bar, so only the strip
   carries the rule. The strip is not sticky, though -- it scrolls away and leaves the
   header alone over the text -- so the header takes the rule over at that point.
   Material toggles `--shadow` on the same scroll that moves the strip out of view.
   The border is declared transparent rather than absent so nothing shifts by a pixel
   when it arrives. */
:root .md-header {
  border-bottom: var(--g-rule-width) solid transparent;
  box-shadow: none;
  color: var(--g-fg);
}

:root .md-header--shadow {
  border-bottom-color: var(--g-border);
  box-shadow: none;
}

:root .md-header__title {
  font-family: var(--g-font-display);
  font-weight: var(--g-display-weight);
  letter-spacing: var(--g-display-tracking);
}

:root .md-header .md-logo {
  color: var(--g-accent-text);
}

/* Four pages, so the nav lives here rather than in a rail. */
:root .md-tabs {
  background: var(--g-bg);
  border-bottom: var(--g-rule-width) solid var(--g-border);
  color: var(--g-fg-muted);
}

:root .md-tabs__link {
  font-family: var(--g-font-display);
  font-size: var(--g-text-xs);
  font-weight: var(--g-display-weight);
  letter-spacing: var(--g-display-tracking);
  margin-top: 0;
  opacity: 1;
  padding-block: 0.7rem;
  text-transform: var(--g-display-transform);
  transition: color var(--g-transition), box-shadow var(--g-transition);
}

:root .md-tabs__link:hover {
  color: var(--g-fg);
}

/* A tab that is merely bolder is hard to spot against a display face that is already
   heavy, so the current page is marked with a rule instead. */
:root .md-tabs__item--active .md-tabs__link {
  box-shadow: inset 0 -2px 0 var(--g-accent);
  color: var(--g-fg);
  opacity: 1;
}

:root .md-footer {
  background: var(--g-surface-alt);
  color: var(--g-fg);
}

:root .md-footer-meta {
  background: var(--g-surface-alt);
  border-top: var(--g-rule-width) solid var(--g-border);
}

:root .md-copyright,
:root .md-copyright__highlight {
  color: var(--g-fg-faint);
  font-size: var(--g-text-2xs);
}

:root .md-social__link svg {
  fill: var(--g-fg-faint);
}

:root .md-social__link:hover svg {
  fill: var(--g-accent-text);
}

:root .md-nav {
  font-family: var(--g-font-body);
  font-size: var(--g-text-xs);
}

:root .md-nav__title {
  font-family: var(--g-font-display);
  text-transform: var(--g-display-transform);
}

:root .md-search__form {
  background: var(--g-surface);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius);
}

:root .md-search__input {
  color: var(--g-fg);
  font-family: var(--g-font-body);
}

:root .md-search__input::placeholder {
  color: var(--g-fg-faint);
}

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

:root .md-typeset .md-button {
  background: transparent;
  border: var(--g-border-width) solid var(--g-border-strong);
  border-radius: var(--g-radius);
  color: var(--g-fg);
  font-family: var(--g-font-display);
  font-size: var(--g-text-xs);
  font-weight: var(--g-display-weight);
  letter-spacing: var(--g-display-tracking);
  padding: 0.5em 1em;
  transition: background var(--g-transition), color var(--g-transition),
    border-color var(--g-transition), box-shadow var(--g-transition);
}

:root .md-typeset .md-button:hover,
:root .md-typeset .md-button:focus-visible {
  background: var(--g-accent);
  border-color: var(--g-accent);
  color: var(--g-on-accent);
}

:root .md-typeset .md-button--primary {
  background: var(--g-accent);
  border-color: var(--g-accent);
  color: var(--g-on-accent);
}

:root .md-typeset .md-button--primary:hover,
:root .md-typeset .md-button--primary:focus-visible {
  background: var(--g-accent-strong);
  border-color: var(--g-accent-strong);
  color: var(--g-on-accent);
}

/* -------------------------------------------------------------- code blocks */

:root .md-typeset pre > code,
:root .md-typeset .highlight > pre > code {
  font-family: var(--g-font-mono);
  font-size: var(--g-text-code);
  line-height: 1.65;
}

:root .md-typeset .highlight {
  background: var(--g-code-bg);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius-lg);
  box-shadow: var(--g-shadow);
  margin: var(--g-gap-lg) 0;
}

:root .md-typeset .highlight pre {
  margin: 0;
}

:root .md-typeset .highlight > pre > code {
  background: transparent;
  padding: 1rem 1.1rem;
}

:root .md-typeset .highlighttable {
  background: var(--g-code-bg);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius-lg);
}

:root .md-typeset .linenos {
  color: var(--g-fg-faint);
}

/* ------------------------------------------------------------ entry masthead */

.entry-head {
  border-bottom: var(--g-rule-width) solid var(--g-border);
  margin-bottom: var(--g-gap-lg);
  padding-bottom: var(--g-gap-lg);
}

.entry-eyebrow {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0 0 0.5rem;
}

.entry-number {
  color: var(--g-accent-text);
  font-family: var(--g-font-display);
  font-size: calc(var(--g-numeral-size) * var(--g-display-scale));
  font-variant-numeric: tabular-nums;
  font-weight: var(--g-display-weight);
  letter-spacing: var(--g-display-tracking);
  line-height: 1;
}

.entry-chip {
  border: var(--g-border-width) solid currentcolor;
  border-radius: var(--g-radius);
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  font-weight: var(--g-display-weight);
  letter-spacing: 0.09em;
  padding: 0.2em 0.6em;
  text-transform: uppercase;
  white-space: nowrap;
}

.entry-chip--beginner { color: var(--g-beginner); }

.entry-chip--intermediate { color: var(--g-intermediate); }

.entry-chip--advanced { color: var(--g-advanced); }

.entry-chip--trivia,
.entry-chip--unknown { color: var(--g-trivia); }

.entry-chip--impact {
  border-color: var(--g-border);
  color: var(--g-fg-faint);
}

.entry-collection {
  color: var(--g-fg-faint);
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.md-typeset .entry-hook {
  color: var(--g-fg-muted);
  font-size: var(--g-text-md);
  font-style: italic;
  margin: 0.3rem 0 0;
}

/* --------------------------------------------------------- entry components */

.entry-actions,
.quiz-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  margin: var(--g-gap-lg) 0 var(--g-gap);
}

.md-typeset .entry-actions .md-button,
.md-typeset .quiz-actions .md-button {
  margin: 0;
}

.ce-note {
  color: var(--g-fg-faint);
  font-size: var(--g-text-xs);
  margin-top: 0.4rem;
}

.md-typeset .entry-predict {
  background: var(--g-accent-wash);
  border-left: 0.25rem solid var(--g-accent);
  border-radius: var(--g-radius);
  font-size: 1.05em;
  margin: var(--g-gap-lg) 0;
  padding: 0.9rem 1.1rem;
}

.md-typeset .entry-predict > :first-child { margin-top: 0; }

.md-typeset .entry-predict > :last-child { margin-bottom: 0; }

.md-typeset .entry-predict::before {
  color: var(--g-accent-text);
  content: "Predict";
  display: block;
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  font-weight: var(--g-display-weight);
  letter-spacing: 0.1em;
  margin-bottom: 0.35rem;
  text-transform: uppercase;
}

.md-typeset details.entry-answer {
  background: var(--g-surface);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius-lg);
  box-shadow: var(--g-shadow);
  margin: var(--g-gap-lg) 0;
}

.md-typeset details.entry-answer > summary {
  background: transparent;
  color: var(--g-fg);
  cursor: pointer;
  font-family: var(--g-font-display);
  font-weight: var(--g-display-weight);
  letter-spacing: var(--g-display-tracking);
  list-style: none;
  padding: 0.7rem 1rem;
  text-transform: var(--g-display-transform);
}

.md-typeset details.entry-answer > summary::-webkit-details-marker { display: none; }

.md-typeset details.entry-answer > summary::marker { content: ""; }

/* Material puts its own marker on this pseudo-element: a 1rem box pinned at
   `left: .6rem`, filled blue and masked into the "note" icon. Overriding `content`
   alone left all of that in place, and because our summary drops Material's 2rem of
   left padding, the box landed on top of the word beside it. Reset the parts we are
   not using -- the fill, the mask, the size, the absolute position -- so what is left
   is the glyph, in the text flow, with room after it. */
.md-typeset details.entry-answer > summary::before {
  background: none;
  color: var(--g-accent-text);
  content: "▸";
  display: inline-block;
  height: auto;
  margin-right: 0.5em;
  -webkit-mask-image: none;
  mask-image: none;
  position: static;
  transition: transform var(--g-transition);
  width: auto;
}

.md-typeset details.entry-answer[open] > summary::before {
  transform: rotate(90deg);
}

.md-typeset details.entry-answer[open] > summary {
  border-bottom: var(--g-rule-width) solid var(--g-border);
}

.md-typeset details.entry-answer > :not(summary) {
  padding-inline: 1rem;
}

.md-typeset details.entry-answer > :last-child {
  padding-bottom: 0.4rem;
}

.md-typeset .entry-takeaway {
  border-left: 0.25rem solid var(--g-accent);
  color: var(--g-fg);
  font-family: var(--g-font-display);
  font-size: var(--g-text-md);
  margin: var(--g-gap-lg) 0;
  padding: 0.3rem 0 0.3rem 1rem;
}

.md-typeset .entry-run {
  background: var(--g-surface-alt);
  border-radius: var(--g-radius);
  color: var(--g-fg-muted);
  font-family: var(--g-font-mono);
  font-size: var(--g-text-xs);
  margin-top: 2rem;
  padding: 0.6rem 0.9rem;
}

.md-typeset .entry-run code {
  background: transparent;
  padding: 0;
}

/* The actions close the page rather than open it. They used to sit above the snippet,
   which meant the first thing an entry offered was a link that ran the code and showed
   the answer -- before the reader had been asked to predict it. */
.md-typeset .entry-actions {
  border-top: var(--g-rule-width) solid var(--g-border);
  margin-top: 2.5rem;
  padding-top: var(--g-gap-lg);
}

/* The pager closes the same block the actions opened, so it takes no rule of its own. */
.md-typeset .entry-actions + .entry-pager,
.md-typeset .entry-actions + .ce-note + .entry-pager {
  border-top: 0;
  margin-top: var(--g-gap);
  padding-top: 0;
}

/* ------------------------------------------------------------- entry pager */

/* Entry pages are kept out of the nav, so Material generates no pagination for them
   and an entry had no way on except the browser's back button. */
.entry-pager {
  align-items: stretch;
  border-top: var(--g-rule-width) solid var(--g-border);
  display: grid;
  gap: var(--g-gap-sm);
  grid-template-columns: 1fr auto 1fr;
  margin-top: 2.5rem;
  padding-top: var(--g-gap);
}

.md-typeset .entry-pager__link {
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius-lg);
  color: var(--g-fg);
  display: grid;
  gap: 0.1rem;
  min-width: 0;
  padding: 0.6rem 0.9rem;
  text-decoration: none;
  transition: border-color var(--g-transition), background var(--g-transition);
}

.md-typeset .entry-pager__link:hover,
.md-typeset .entry-pager__link:focus-visible {
  background: var(--g-surface);
  border-color: var(--g-accent);
  color: var(--g-fg);
}

/* Next sits in the third column whether or not there is a previous entry, so the
   first page of a collection does not have its only link slide to the left. */
.md-typeset .entry-pager__link--prev {
  grid-column: 1;
}

.md-typeset .entry-pager__link--next {
  grid-column: 3;
  text-align: end;
}

.entry-pager__direction {
  color: var(--g-fg-faint);
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.entry-pager__title {
  font-family: var(--g-font-display);
  font-size: var(--g-text-sm);
  font-weight: var(--g-display-weight);
  /* Grid items are min-width:auto, which is what stops an over-long title ellipsing
     and lets it widen its column instead. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.md-typeset .entry-pager__index {
  align-self: center;
  color: var(--g-fg-muted);
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  grid-column: 2;
  letter-spacing: 0.09em;
  padding: 0.6rem 0.4rem;
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
}

.md-typeset .entry-pager__index:hover {
  color: var(--g-accent-text);
}

/* -------------------------------------------------------------------- hero */

.grail-hero {
  border-bottom: var(--g-rule-width) solid var(--g-border);
  margin-bottom: 2.5rem;
  padding-bottom: 1.8rem;
}

.md-typeset .grail-hero h1 {
  margin-bottom: 0.7rem;
}

.md-typeset .grail-hero__lede {
  color: var(--g-fg-muted);
  font-size: var(--g-text-lg);
  line-height: 1.55;
  margin: 0 0 1.4rem;
  max-width: var(--g-measure);
}

/* Markdown wraps a run of buttons in a paragraph, so the flex row has to be set on
   that paragraph rather than on the div around it. */
.grail-actions,
.md-typeset .grail-actions > p {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  margin: 0;
}

.md-typeset .grail-actions .md-button {
  margin: 0;
}

/* Every list we lay out ourselves needs the `:root .md-typeset` prefix, and all of it is
   load-bearing. Material claims these lists at three different weights:

     .md-typeset ul                    (0,1,1)  list-style-type: disc
     .md-typeset ul:not([hidden])      (0,2,1)  display: flow-root
     [dir=ltr] .md-typeset ul li       (0,2,2)  margin-left: 1.25em

   A bare `.entry-list` (0,1,0) loses the bullet; `.md-typeset .entry-list` (0,2,0) also
   loses `display`, so the card grids silently rendered as stacked blocks indented
   1.25em past the search field above them. `:root` buys the extra class weight, which
   is the same trick the rest of this file uses on Material's own components. */
:root .md-typeset .grail-hero__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.5rem;
  list-style: none;
  /* Pulled left by the figures' own padding, so the first one still starts on the
     column edge with the heading above it. */
  margin: 1.6rem 0 0 -0.8rem;
  padding: 0;
}

:root .md-typeset .grail-hero__stats li {
  margin: 0;
}

/* Each figure is a way in, not an ornament: it opens Browse already filtered. */
.md-typeset .grail-stat {
  border: var(--g-border-width) solid transparent;
  border-radius: var(--g-radius);
  color: inherit;
  display: block;
  padding: 0.4rem 0.8rem;
  text-decoration: none;
  transition: border-color var(--g-transition), background var(--g-transition);
}

.md-typeset .grail-stat:hover,
.md-typeset .grail-stat:focus-visible {
  background: var(--g-surface);
  border-color: var(--g-border);
  color: inherit;
}

.grail-stat__value {
  color: var(--g-accent-text);
  display: block;
  font-family: var(--g-font-display);
  font-size: var(--g-text-xl);
  font-variant-numeric: tabular-nums;
  font-weight: var(--g-display-weight);
  line-height: 1.1;
}

.grail-stat__label {
  color: var(--g-fg-faint);
  display: block;
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

/* ------------------------------------------------------------- collections */

:root .md-typeset .grail-collections {
  display: grid;
  gap: var(--g-gap);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  list-style: none;
  margin: var(--g-gap-lg) 0 2.5rem;
  padding: 0;
}

:root .md-typeset .grail-collections > li {
  background: var(--g-surface);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius-lg);
  margin: 0;
  padding: 1rem 1.1rem 1.2rem;
}

.md-typeset .grail-collection__count {
  color: var(--g-fg-faint);
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  letter-spacing: 0.09em;
  margin: 0;
  text-transform: uppercase;
}

.md-typeset .grail-collection h3 {
  font-size: var(--g-text-md);
  margin: 0.15rem 0 0.5rem;
}

.md-typeset .grail-collection h3 a {
  text-decoration: none;
}

.md-typeset .grail-collection h3 a:hover {
  text-decoration: underline;
}

.md-typeset .grail-collection p:last-child {
  color: var(--g-fg-muted);
  font-size: var(--g-text-sm);
  margin: 0;
}

/* ---------------------------------------------------------- entry browser */

.entry-browser {
  margin: var(--g-gap-lg) 0 2.5rem;
}

.entry-filters {
  display: grid;
  gap: var(--g-gap);
  margin-bottom: var(--g-gap);
}

.entry-filters .entry-search {
  margin-bottom: var(--g-gap-xs);
}

.entry-search {
  background: var(--g-surface);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius);
  color: var(--g-fg);
  flex: 1 1 14rem;
  font: inherit;
  font-family: var(--g-font-body);
  padding: 0.55rem 0.75rem;
}

.entry-search::placeholder {
  color: var(--g-fg-faint);
}

.entry-search:focus-visible {
  border-color: var(--g-accent);
}

.entry-chipset {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

/* The label takes a line of its own -- `flex-basis: 100%` in a wrapping row -- so the
   chips start on the same left edge as the search field above them. Set inline, it
   indented every chip past the one control it was meant to describe. */
.entry-chipset__label {
  color: var(--g-fg-faint);
  flex: 0 0 100%;
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  letter-spacing: 0.09em;
  margin-bottom: 0.1rem;
  text-transform: uppercase;
}

.entry-filter {
  background: transparent;
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius);
  color: var(--g-fg-muted);
  cursor: pointer;
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  font-weight: var(--g-display-weight);
  letter-spacing: 0.06em;
  padding: 0.4em 0.75em;
  text-transform: uppercase;
  transition: background var(--g-transition), color var(--g-transition),
    border-color var(--g-transition);
}

.entry-filter:hover {
  border-color: var(--g-accent);
  color: var(--g-fg);
}

.entry-filter[aria-pressed="true"] {
  background: var(--g-accent);
  border-color: var(--g-accent);
  color: var(--g-on-accent);
}

.entry-count {
  color: var(--g-fg-faint);
  font-family: var(--g-font-mono);
  font-size: var(--g-text-xs);
  margin: 0 0 var(--g-gap);
}

:root .md-typeset .entry-list {
  display: grid;
  gap: 0.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

:root .md-typeset .entry-list li {
  margin: 0;
}

.md-typeset .entry-card {
  align-items: baseline;
  background: var(--g-surface);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius-lg);
  color: var(--g-fg);
  display: grid;
  gap: 0.15rem 0.9rem;
  grid-template-columns: 3rem 1fr auto;
  padding: 0.7rem 0.9rem;
  text-decoration: none;
  transition: border-color var(--g-transition), box-shadow var(--g-transition),
    transform var(--g-transition);
}

.md-typeset .entry-card:hover,
.md-typeset .entry-card:focus-visible {
  border-color: var(--g-accent);
  box-shadow: var(--g-shadow-raised);
  color: var(--g-fg);
}

.entry-card__number {
  color: var(--g-accent-text);
  font-family: var(--g-font-mono);
  font-size: var(--g-text-sm);
  font-variant-numeric: tabular-nums;
  grid-column: 1;
  grid-row: 1 / span 2;
}

.entry-card__title {
  font-family: var(--g-font-display);
  font-weight: var(--g-display-weight);
  grid-column: 2;
  letter-spacing: var(--g-display-tracking);
}

.entry-card__hook {
  color: var(--g-fg-muted);
  font-size: var(--g-text-sm);
  grid-column: 2;
}

.entry-card__level {
  grid-column: 3;
  grid-row: 1 / span 2;
}

.entry-empty {
  border: var(--g-border-width) dashed var(--g-border-strong);
  border-radius: var(--g-radius);
  color: var(--g-fg-muted);
  padding: 1.2rem;
  text-align: center;
}

/* -------------------------------------------------------------------- quiz */

.quiz-controls {
  align-items: end;
  display: grid;
  gap: 0.9rem;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  margin: var(--g-gap-lg) 0;
}

.quiz-controls label:not(.quiz-checkbox) {
  display: grid;
  font-family: var(--g-font-display);
  font-size: var(--g-text-xs);
  font-weight: var(--g-display-weight);
  gap: 0.3rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.quiz-controls select {
  background: var(--g-surface);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius);
  color: var(--g-fg);
  font: inherit;
  font-family: var(--g-font-body);
  font-size: var(--g-text-sm);
  letter-spacing: normal;
  padding: 0.55rem;
  text-transform: none;
  width: 100%;
}

.quiz-checkbox {
  align-items: center;
  color: var(--g-fg-muted);
  display: flex;
  font-size: var(--g-text-sm);
  gap: 0.45rem;
  min-height: 2.45rem;
}

.quiz-summary {
  align-items: center;
  border-top: var(--g-rule-width) solid var(--g-border);
  display: flex;
  flex-wrap: wrap;
  gap: var(--g-gap);
  justify-content: space-between;
  margin: var(--g-gap) 0;
  padding-top: var(--g-gap);
}

#quiz-progress {
  color: var(--g-fg-muted);
  font-family: var(--g-font-mono);
  font-size: var(--g-text-xs);
}

.quiz-link-button {
  background: none;
  border: 0;
  color: var(--g-accent-text);
  cursor: pointer;
  font: inherit;
  font-family: var(--g-font-body);
  font-size: var(--g-text-code);
  padding: 0.25rem;
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

.quiz-link-button:hover {
  color: var(--g-accent-strong);
}

.quiz-card {
  background: var(--g-surface);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius-lg);
  box-shadow: var(--g-shadow);
  margin-top: var(--g-gap-lg);
  padding: clamp(1rem, 3vw, 1.6rem);
  scroll-margin-top: 4rem;
}

.quiz-kicker {
  color: var(--g-fg-faint);
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  font-weight: var(--g-display-weight);
  letter-spacing: 0.09em;
  margin: 0;
  text-transform: uppercase;
}

.quiz-code {
  max-height: 30rem;
  overflow: auto;
}

.md-typeset .quiz-code {
  background: var(--g-code-bg);
  border: var(--g-border-width) solid var(--g-border);
  border-radius: var(--g-radius);
}

.md-typeset .quiz-code > code {
  font-family: var(--g-font-mono);
  font-size: var(--g-text-code);
}

.quiz-question {
  font-size: var(--g-text-md);
  margin: 1rem 0;
}

.quiz-answer {
  border-left: 0.25rem solid var(--g-accent);
  margin: var(--g-gap-lg) 0;
  padding: 0.15rem 0 0.15rem 1rem;
}

.quiz-rating {
  border-top: var(--g-rule-width) solid var(--g-border);
  margin-top: 1.25rem;
  padding-top: 1rem;
}

.md-typeset .quiz-rating p {
  color: var(--g-fg-muted);
  font-size: var(--g-text-sm);
}

.quiz-rating button {
  background: var(--g-bg);
  border: var(--g-border-width) solid var(--g-border-strong);
  border-radius: var(--g-radius);
  color: var(--g-fg);
  cursor: pointer;
  font-family: var(--g-font-display);
  font-size: var(--g-text-xs);
  font-weight: var(--g-display-weight);
  margin: 0 0.45rem 0.45rem 0;
  padding: 0.5rem 0.8rem;
  transition: background var(--g-transition), color var(--g-transition),
    border-color var(--g-transition);
}

.quiz-rating button:hover,
.quiz-rating button:focus-visible,
.quiz-rating button[aria-pressed="true"] {
  background: var(--g-accent);
  border-color: var(--g-accent);
  color: var(--g-on-accent);
}

.quiz-empty {
  border: var(--g-border-width) dashed var(--g-border-strong);
  border-radius: var(--g-radius);
  color: var(--g-fg-muted);
  margin-top: var(--g-gap-lg);
  padding: 1rem;
}

/* ------------------------------------------------------------ theme picker */

.grail-picker {
  position: relative;
}

.grail-picker__toggle {
  background: transparent;
  border: 0;
  border-radius: var(--g-radius);
  color: currentcolor;
  cursor: pointer;
  display: grid;
  height: 2.4rem;
  place-items: center;
  width: 2.4rem;
}

.grail-picker__toggle:hover,
.grail-picker__toggle[aria-expanded="true"] {
  color: var(--g-accent-text);
}

.grail-picker__toggle svg {
  fill: currentcolor;
  height: 1.2rem;
  width: 1.2rem;
}

.grail-picker__menu {
  /* One row is the tile plus its padding. Eight rows fit before the list starts to
     scroll, which covers the shipped set and leaves room to grow without the panel
     turning into a page of its own. */
  --grail-picker-row: 2.85rem;

  background: var(--g-bg);
  border: var(--g-border-width) solid var(--g-border-strong);
  border-radius: var(--g-radius-lg);
  box-shadow: var(--g-shadow-raised), 0 8px 30px rgba(0, 0, 0, 0.18);
  color: var(--g-fg);
  display: grid;
  gap: 0.3rem;
  inset-inline-end: 0;
  max-width: 18rem;
  min-width: 14rem;
  padding: 0.45rem;
  position: absolute;
  top: calc(100% + 0.4rem);
  z-index: 10;
}

.grail-picker__menu[hidden] {
  display: none;
}

.grail-picker__title {
  color: var(--g-fg-faint);
  font-family: var(--g-font-display);
  font-size: var(--g-text-2xs);
  letter-spacing: 0.1em;
  margin: 0.1rem 0.3rem 0;
  text-transform: uppercase;
}

.grail-picker__list {
  display: grid;
  gap: 0.1rem;
  max-height: calc(var(--grail-picker-row) * 8);
  /* Both axes are declared on purpose. Leaving overflow-x unset would compute it to
     `auto` alongside overflow-y, which is what let a long name scroll the list. */
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.grail-picker__option {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--g-radius);
  color: var(--g-fg);
  cursor: pointer;
  display: flex;
  gap: 0.55rem;
  /* Lets the name shrink below its own width instead of widening the row. */
  min-width: 0;
  padding: 0.3rem 0.45rem;
  text-align: start;
  width: 100%;
}

.grail-picker__option[hidden] {
  display: none;
}

.grail-picker__option:hover,
.grail-picker__option:focus-visible {
  background: var(--g-surface-alt);
}

.grail-picker__option[aria-checked="true"] {
  background: var(--g-accent-wash);
}

/* The tile is poster-shaped and carries the theme's monogram. Its colors, type and
   corner radius come from generated per-theme rules (see tools/themes.py), so it
   previews the theme it names rather than inheriting the active one. A theme that
   ships artwork gets it as a background image and hides the monogram. */
.grail-picker__poster {
  align-items: center;
  aspect-ratio: 2 / 3;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  border: 1px solid var(--g-border-strong);
  display: flex;
  flex: 0 0 auto;
  justify-content: center;
  overflow: hidden;
  /* At 1.5rem the monogram inside was smaller than the type around it. */
  width: 1.85rem;
}

.grail-picker__poster-title {
  font-size: var(--g-text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
}

.grail-picker__name {
  font-family: var(--g-font-display);
  font-size: var(--g-text-sm);
  font-weight: var(--g-display-weight);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

:root .md-typeset pre > code {
  font-family: var(--g-font-mono);
  font-size: var(--g-text-code);
}

/* --------------------------------------------------------------- responsive */

/* Phones. The two multipliers narrow the whole type system at once; everything below
   them is about touch rather than size -- controls that are comfortable with a mouse
   are too small for a thumb. */
@media (max-width: 600px) {
  :root body {
    --g-text-scale: 0.96;
    --g-display-scale: 0.72;
    --g-gap-lg: 1.15rem;
  }

  /* Actions become full-width rows: three narrow buttons side by side is a mis-tap. */
  .entry-actions,
  .quiz-actions {
    display: grid;
  }

  .md-typeset .entry-actions .md-button,
  .md-typeset .quiz-actions .md-button {
    text-align: center;
  }

  /* 44px is the smallest comfortable touch target. These are inline-block by default,
     so growing them without flex would leave the label sitting at the top edge. */
  .md-typeset .md-button,
  .entry-filter,
  .quiz-rating button,
  .quiz-link-button {
    align-items: center;
    display: inline-flex;
    justify-content: center;
    min-height: 2.75rem;
  }

  .entry-search,
  .quiz-controls select {
    min-height: 2.75rem;
  }

  .grail-picker__toggle {
    height: 2.75rem;
    width: 2.75rem;
  }

  .grail-picker__option {
    min-height: 3rem;
  }

  /* The menu is anchored to the right edge, so cap it against the viewport rather
     than a fixed rem width it could exceed on a narrow phone. */
  .grail-picker__menu {
    max-width: min(18rem, calc(100vw - 1.5rem));
  }

  /* The numeral and the title stop competing for the same line. */
  .md-typeset .entry-card {
    grid-template-columns: 2.25rem 1fr;
  }

  .entry-card__level {
    grid-column: 2;
    grid-row: 3;
    justify-self: start;
    margin-top: 0.35rem;
  }

  .grail-hero__stats {
    gap: 0.2rem 0.4rem;
  }

  /* Three columns of nav become one: a truncated title in a 33%-wide box tells the
     reader nothing about where the link goes. */
  .entry-pager {
    grid-template-columns: 1fr;
  }

  .md-typeset .entry-pager__link--prev,
  .md-typeset .entry-pager__link--next {
    grid-column: 1;
    text-align: start;
  }

  .md-typeset .entry-pager__index {
    grid-column: 1;
    grid-row: 3;
    justify-self: start;
    padding-inline: 0;
  }

  .quiz-summary {
    align-items: flex-start;
    flex-direction: column;
    gap: 0.4rem;
  }
}

/* Narrow phones. Uppercase display faces set at a large size are the first thing to
   overflow here, so the display scale drops again and the filters stack. */
@media (max-width: 400px) {
  :root body {
    --g-display-scale: 0.62;
  }

  .entry-filters {
    gap: 0.5rem;
  }

  .entry-chipset {
    width: 100%;
  }

  .grail-hero__stats {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }

  .entry-filter {
    flex: 1 1 auto;
  }

  .md-typeset .entry-card {
    grid-template-columns: 1fr;
  }

  .entry-card__number {
    grid-column: 1;
    grid-row: 1;
  }

  .entry-card__title,
  .entry-card__hook,
  .entry-card__level {
    grid-column: 1;
  }
}
