/* Pysae brand theme, aligned with web.pysae.com.
 *
 * Brand values come from the site's own CSS custom properties:
 *   --primary   #00b871   --secondary #0a4b4d   --soft-bg #e6faf3
 * Typeface is Poppins, self-hosted here: the documentation must not fetch any
 * external host, and the marketing site loads it from Google Fonts.
 */

/* Poppins — SIL Open Font License 1.1, subset to latin and latin-ext. */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: optional;
  src: url("../fonts/poppins-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
    U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: optional;
  src: url("../fonts/poppins-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: optional;
  src: url("../fonts/poppins-600-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
    U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: optional;
  src: url("../fonts/poppins-600-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: optional;
  src: url("../fonts/poppins-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
    U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 700;
  font-display: optional;
  src: url("../fonts/poppins-700-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
    U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

:root {
  --pysae-primary: #00b871;
  --pysae-secondary: #0a4b4d;
  --pysae-soft-bg: #e6faf3;
  /* Darkened primary: #00b871 only reaches 2.6:1 on white, below the 4.5:1
     WCAG AA floor for body text, so links use this 5:1 variant instead. */
  --pysae-primary-readable: #00814f;

  /* The theme builds --md-text-font-family from --md-text-font, so setting the
     composed property directly would be overwritten. */
  --md-text-font: "Poppins";
}

[data-md-color-scheme="default"] {
  --md-primary-fg-color: var(--pysae-secondary);
  --md-primary-fg-color--light: #14676a;
  --md-primary-fg-color--dark: #063234;
  --md-primary-bg-color: #fff;
  --md-primary-bg-color--light: #ffffffb3;

  --md-accent-fg-color: var(--pysae-primary);
  --md-accent-fg-color--transparent: #00b8711a;
  --md-accent-bg-color: #fff;

  --md-typeset-a-color: var(--pysae-primary-readable);
}

/* On the dark scheme the brand green sits on a dark surface, where it clears
   AA on its own — no darkened variant needed. */
[data-md-color-scheme="slate"] {
  --md-primary-fg-color: #063234;
  --md-primary-fg-color--light: var(--pysae-secondary);
  --md-primary-fg-color--dark: #041f20;

  --md-accent-fg-color: var(--pysae-primary);
  --md-accent-fg-color--transparent: #00b8711a;

  --md-typeset-a-color: var(--pysae-primary);
}

/* Headings mirror the marketing site: heavy Poppins in the deep teal, with the
   tight tracking the brand uses on display text. */
.md-typeset h1,
.md-typeset h2,
.md-typeset h3 {
  font-weight: 600;
  letter-spacing: -0.01em;
}

[data-md-color-scheme="default"] .md-typeset h1,
[data-md-color-scheme="default"] .md-typeset h2 {
  color: var(--pysae-secondary);
}

.md-typeset h1 {
  font-weight: 700;
}

/* Brand-tinted admonitions and quotes, echoing the site's soft green blocks. */
[data-md-color-scheme="default"] .md-typeset .admonition.info,
[data-md-color-scheme="default"] .md-typeset details.info {
  background-color: var(--pysae-soft-bg);
}

.md-typeset .md-button--primary {
  background-color: var(--pysae-primary);
  border-color: var(--pysae-primary);
  color: #fff;
}

/* Header selectors (language, code language, visibility). The theme's .8rem
   reads oversized for dropdown entries, all the more with three selectors. */
.md-select__list {
  font-size: 0.65rem;
}

/* The theme closes a menu on a delay (opacity .25s late, max-height half a
   second late). With three adjacent selectors, moving from one to the next
   leaves the previous menu on screen under the one opening. Closing without a
   delay keeps a single menu visible at a time. */
.md-select__inner {
  transition: transform 0.2s, opacity 0.2s, max-height 0ms;
}

/* The language selector shows a flag rather than an icon, so it carries a text
   glyph where its neighbours carry an SVG. Sized to the box the theme gives
   those, so the three buttons keep the same footprint in the header. */
.pysae-header-flag > span {
  align-items: center;
  display: flex;
  font-size: 0.85rem;
  height: 1rem;
  justify-content: center;
  line-height: 1;
  width: 1rem;
}

/* One menu at a time: as soon as a selector is hovered or focused, every other
   menu closes instantly instead of lingering under the one opening. Both
   combinators are needed — `~` reaches the siblings that follow the active
   selector, `:has()` those that precede it. */
.md-header__option:hover ~ .md-header__option .md-select__inner,
.md-header__option:focus-within ~ .md-header__option .md-select__inner,
.md-header__option:has(~ .md-header__option:hover) .md-select__inner,
.md-header__option:has(~ .md-header__option:focus-within) .md-select__inner {
  max-height: 0;
  opacity: 0;
  transition: none;
}

/* The theme moves every table into a scrolling wrapper once its script runs,
   and that wrapper is taller than the bare table it replaces: the inline-block
   sits on a text baseline, which reserves descender space under it, and it
   carries a bottom margin the bare table does not have. Everything below the
   table therefore dropped by ~10px on each load, once the wrapper appeared.

   The gap is the descender space of the line box the inline-block sits in, so
   it goes away with that line's strut. Zeroing the font size on the wrapper
   collapses the strut and nothing else: the table declares its own size. */
.md-typeset__scrollwrap {
  font-size: 0;
}

.md-typeset__table {
  margin-bottom: 0;
}

/* The theme tightens the margin of whatever follows a table
   (`table:not([class])+*`), but that selector only holds while the table is
   still a sibling — its own script then wraps the table and the rule silently
   stops applying, so the rest of the page moved up. Carrying it over to the
   wrapper keeps the spacing the theme asked for, in both states.

   Scoped to the article so it outweighs the theme's own `.md-typeset h2`,
   which is what the original rule has to beat too. */
.md-typeset .md-typeset__scrollwrap + * {
  margin-top: 1.5em;
}

/* Until it is wrapped the table is inline-level, so the line it sits on
   reserves descender space underneath it — space the wrapped table does not
   take. Making it a block up front removes that difference too. */
.md-typeset > table:not([class]) {
  display: table;
}

/* Chips naming the variant being read, detached above the table of contents and
   indented to line up with its entries, so they read as a marker on the page
   rather than as a heading of the contents below them. */
.pysae-variant-chips {
  align-items: center;
  /* Lifted above the contents that follow it in the document: without this the
     table of contents paints over the open menu. */
  position: relative;
  z-index: 2;
  /* The theme includes this partial twice — once for the sidebar, once folded
     under the active item of the mobile drawer. The chips belong to the first. */
  display: none;
  /* One line: stacked, the three read as a list to work through rather than as
     one marker. They are flush with the column instead of indented onto the
     contents entries — three labels and their gaps need every pixel of a
     12.1rem column. */
  align-items: center;
  flex-wrap: nowrap;
  gap: 0.2rem;
  margin-bottom: 0.9rem;
  /* Matches where the contents entries start: their own padding, plus the
     offset of the navigation box that holds them. */
  padding-left: 0.8rem;
}

.md-sidebar--secondary .pysae-variant-chips {
  display: flex;
}

/* The flag rides in a chip like its neighbours, glyph alone — three labels side
   by side do not clear a 12.1rem column. The name it stands for is on the
   button as its accessible name, since a flag sequence is read poorly aloud and
   falls back to two letters where it is not drawn at all. */
.pysae-variant-chip--flag {
  padding-left: 0.3rem;
  padding-right: 0.3rem;
}

/* Each chip carries the icon its axis has in the header, so the two places are
   recognisably the same control. Sized to the label rather than to the theme's
   header button, which is built for a much larger target. */
.pysae-variant-chip__icon svg {
  display: block;
  height: 0.7rem;
  width: 0.7rem;
}

/* Emoji are drawn taller than label text at the same size. Pinning the glyph's
   line box to the label's keeps the pill the height of its neighbours rather
   than stretching it. */
.pysae-variant-chip__flag {
  font-size: 0.6rem;
  /* Set to the line box a label produces at this chip's size, so the flag chip
     is exactly as tall as the ones beside it. */
  line-height: 0.85rem;
}

/* Outlined rather than filled: these name the build, they are not a call to
   action. The brand green is taken in its darkened form, since the raw one
   reaches 2.59:1 on white — the same reason links already use it. */
.pysae-variant-chip {
  align-items: center;
  background-color: transparent;
  border: 0.05rem solid var(--pysae-primary-readable);
  display: inline-flex;
  gap: 0.2rem;
  border-radius: 1rem;
  color: var(--pysae-primary-readable);
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  /* Kept tight: three of these and their gaps have to clear a 12.1rem column,
     and the longest labels leave little room. */
  padding: 0.1rem 0.4rem;
  white-space: nowrap;
}

/* Last resort, and only that: a longer translation, or a font whose metrics run
   wider than the ones measured against, would otherwise push the row past the
   column. Trimming a label beats overflowing. */
.pysae-variant-chips .md-select {
  min-width: 0;
}

.pysae-variant-chip {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}


/* On a dark surface the raw brand green is the legible one. */
[data-md-color-scheme="slate"] .pysae-variant-chip {
  border-color: var(--pysae-primary);
  color: var(--pysae-primary);
}

/* Category and language are metadata beside the code language, so they stay
   neutral instead of competing with it — only the language the examples are
   written in is worth the brand colour. It also settles the brand teal, which
   has no tone that separates from the dark scheme without inventing one. */
.pysae-variant-chip--scope,
.pysae-variant-chip--flag,
[data-md-color-scheme="slate"] .pysae-variant-chip--scope,
[data-md-color-scheme="slate"] .pysae-variant-chip--flag {
  border-color: var(--md-default-fg-color--lighter);
  color: var(--md-default-fg-color--light);
}

/* The entry matching the current variant, so each menu shows what is active. */
.md-select__link[aria-current="true"] {
  color: var(--md-accent-fg-color);
  font-weight: 600;
}

/* Inert selector entries: the dev server holds a single variant, so switching
   is shown as unavailable rather than linking to a path it does not serve. */
.md-select__link--inert {
  cursor: default;
  opacity: 0.5;
}

.md-select__link--inert[aria-current="true"] {
  opacity: 1;
}

/* The search box stopped at the content column while the header ran on to the
   width of the contents beside it, leaving the field narrow for no reason.

   Scoped to the breakpoint where that contents column appears — below it the
   header lays the search out differently. */
@media screen and (min-width: 76.25em) {
  /* The header keeps a column for the repository link. None is configured, so
     it renders without content and holds width the search can have. Matched on
     having no child element rather than `:empty`, which the template's own
     whitespace already defeats — and it gives the column back the moment a
     repository is set. */
  .md-header__source:not(:has(*)) {
    display: none;
  }

  .md-search {
    /* Sized and pushed to sit over the contents column rather than stretching
       across the header. The sidebar is 12.1rem, less the .4rem the header
       already insets on that side, so the field starts where that column
       starts. */
    flex: 0 0 auto;
    margin-left: auto;
    width: 11.7rem;
  }

  .md-search__button {
    width: 100%;
  }
}

/* Pages differ in length, so the viewport scrollbar came and went as you moved
   between them and the page jumped by its width each time — 15px here, which is
   what reads as the scrollbar flickering.

   The theme asks for `scrollbar-gutter: stable`, which should reserve the space
   whether or not the page overflows, but the gutter is measurably not reserved.
   Declaring the scrollbar always present holds the width steady regardless. */
html {
  overflow-y: scroll;
}

/* The chips are buttons: they open the same menus the header does, through the
   theme's own `.md-select`, which reveals its list on hover and on focus — so a
   click opens one without a line of script. */
.pysae-variant-chip {
  cursor: pointer;
  font-family: inherit;
}

/* Each menu hangs from whichever edge of its chip leaves it room, since the row
   spans a narrow column: the first grows rightwards from its left edge, the last
   leftwards from its right edge, and the one between them opens centred.

   The horizontal share of the transform is held in a variable because the
   translate also carries the open/close animation, which is the same for all
   three and stated once below. */
.pysae-variant-chips .md-select__inner {
  --pysae-menu-shift: 0;
  left: 0;
  transform: translate3d(var(--pysae-menu-shift), 0.3rem, 0);
}

.pysae-variant-chips .md-select:has(.pysae-variant-chip--scope) .md-select__inner {
  --pysae-menu-shift: -50%;
  left: 50%;
}

.pysae-variant-chips .md-select:has(.pysae-variant-chip--flag) .md-select__inner {
  left: auto;
  right: 0;
}

.pysae-variant-chips .md-select:focus-within .md-select__inner,
.pysae-variant-chips .md-select:hover .md-select__inner {
  transform: translate3d(var(--pysae-menu-shift), 0, 0);
}

/* Stacked, a menu opens over the chips beneath it, which follow it in the
   document and would otherwise paint on top. The open one is raised for as
   long as it is open. */
.pysae-variant-chips .md-select:focus-within,
.pysae-variant-chips .md-select:hover {
  z-index: 3;
}

/* One menu at a time here as well, on the same reasoning as the header. */
.pysae-variant-chips .md-select:hover ~ .md-select .md-select__inner,
.pysae-variant-chips .md-select:focus-within ~ .md-select .md-select__inner,
.pysae-variant-chips .md-select:has(~ .md-select:hover) .md-select__inner,
.pysae-variant-chips .md-select:has(~ .md-select:focus-within) .md-select__inner {
  max-height: 0;
  opacity: 0;
  transition: none;
}
