/*
 * Grilled Cheese docs site.
 *
 * This REPLACES Asciidoctor's bundled stylesheet (:linkcss: + :stylesheet:),
 * so it has to cover everything the HTML5 backend can emit, headings, the
 * TOC, admonitions, listings, tables, footnotes, not just the parts the
 * current pages happen to use. A new page that reaches for an unstyled block
 * is the failure mode to watch for.
 *
 * The palette is the app's: toasted-cheddar accent on warm cream in light,
 * warm brown in dark. Values are lifted from lib/theme/app_theme.dart in the
 * dissipate repo so the docs and the product read as one thing.
 */

/* ---------------------------------------------------------------- tokens */

:root {
  --gc-accent: #b26a0c;
  --gc-accent-bright: #e8951c;

  --gc-surface: #fdf6e7;
  --gc-page: #f7edd9;
  --gc-hairline: #eadbbe;
  --gc-ink: #2a2012;
  --gc-ink-muted: #7c6f57;
  --gc-code-bg: #f2e6cd;

  --gc-measure: 46rem;

  /* The height of the fixed site nav, and the space <body> reserves for it.
     Both read this one token, and so do the TOC rail's offset and the
     scroll-margin on headings, so the two-row narrow header below only has to
     redefine the token and everything that depends on the header's height
     follows.  A hard-coded height anywhere else is a bug waiting for the next
     breakpoint. */
  --gc-nav-height: 5.5rem;

  /* The two stacks a theme can select between, and the one in force. themes.css
     reassigns --gc-font per theme (Hacker is monospace, Merriweather serif);
     everything else reads --gc-font and does not care which. */
  --gc-font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --gc-font-mono: "SF Mono", ui-monospace, "JetBrains Mono", Menlo, Consolas,
    monospace;
  --gc-font: var(--gc-font-sans);

  /* Wireframes are monochrome renders on a light ground, so a dark theme
     inverts them rather than leaving a glaring white rectangle mid-page. See
     the .imageblock.wireframe rule. */
  --gc-wf-invert: 0;
}

/* The header collapses to a single row once there is room for the brand, the
   nav links and both controls side by side.  The breakpoint is deliberately
   generous rather than tuned to English: the nav labels are translated, and
   "Benutzerhandbuch" next to "KI-Werkzeuge" is half as wide again as "User
   Guide" next to "AI Tools".  It is the same 62rem the TOC rail uses, so the
   wide layout arrives all at once. */
@media (min-width: 62rem) {
  :root {
    --gc-nav-height: 3.5rem;
  }
}

@media (prefers-color-scheme: dark) {
  :root {
    --gc-accent: #f0be43;
    --gc-accent-bright: #f0be43;
    --gc-surface: #241a12;
    --gc-page: #1a130d;
    --gc-hairline: #3a2e22;
    --gc-ink: #ede8de;
    --gc-ink-muted: #98917f;
    --gc-code-bg: #2f2419;
    --gc-wf-invert: 1;
  }
}

/* ------------------------------------------------------------------ base */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  padding-top: var(--gc-nav-height);
  background: var(--gc-page);
  color: var(--gc-ink);
  font-family: var(--gc-font);
  font-size: 17px;
  line-height: 1.65;
  text-rendering: optimizeLegibility;
}

a {
  color: var(--gc-accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

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

img {
  max-width: 100%;
  height: auto;
}

/* ------------------------------------------------------------- site nav */

/*
 * The bar carries four things: the brand, three translated nav links, the
 * theme picker and the language menu.  Below 62rem that is more than fits on
 * one line of a phone, so the bar becomes two rows rather than wrapping at
 * whatever point the current locale's words happen to run out of room:
 *
 *   narrow                          wide (>= 62rem)
 *   [mark Grilled Cheese]  [th][ln] [mark Grilled Cheese] [links] [th] [ln]
 *   [User Guide  AI Tools  About  ]
 *
 * Two rows rather than a hamburger because the site has three nav links, and
 * hiding three links behind a button that needs JavaScript to open would cost
 * more than the 2rem of screen it saves.  Everything stays visible, and
 * everything except the theme picker works with JavaScript off.
 *
 * The row heights add up to --gc-nav-height exactly, at both layouts, which is
 * what keeps <body>'s reservation honest.  Change one, change the token.
 *
 * New rules here use logical properties (margin-inline-start, inset-inline-end)
 * rather than the physical left/right the rest of this file uses.  The chrome
 * is the part that has to mirror in Arabic, and a property that mirrors itself
 * cannot fall out of step with css/rtl.css.
 */
.site-nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 20;
  height: var(--gc-nav-height);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: center;
  gap: 0 1rem;
  padding: 0 0.9rem;
  background: var(--gc-surface);
  border-bottom: 1px solid var(--gc-hairline);
}

/* The brand is the flexible one.  It shrinks and clips before the controls
   next to it are pushed onto a line of their own, which is what stops row one
   ever becoming two rows and leaving the page's top reservation short. */
.site-nav__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 3rem;
  flex: 0 1 auto;
  min-width: 0;
  font-weight: 650;
  color: var(--gc-ink);
  text-decoration: none;
  letter-spacing: -0.01em;
}

.site-nav__brand img {
  flex: none;
}

.site-nav__brand span {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* On the narrowest phones the wordmark goes entirely: the mark alone still
   says whose site this is, and the row has a theme picker and a language menu
   to fit as well. */
@media (max-width: 24rem) {
  .site-nav__brand span {
    display: none;
  }
}

/* Row two on a phone: full-basis, so it wraps below the brand and the
   controls whatever the locale's labels measure.  It scrolls rather than
   wraps in the extreme case, because a wrapped third row would leave content
   hidden under a bar taller than the space reserved for it. */
.site-nav__links {
  order: 2;
  flex: 1 1 100%;
  display: flex;
  align-items: center;
  height: 2.5rem;
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.85rem;
  overflow-x: auto;
  scrollbar-width: none;
}

.site-nav__links::-webkit-scrollbar {
  display: none;
}

.site-nav__links li {
  white-space: nowrap;
}

.site-nav__links a {
  color: var(--gc-ink-muted);
  text-decoration: none;
}

.site-nav__links a:hover {
  color: var(--gc-accent);
}

/* The theme picker and the language menu, as one group.  The group is what
   the auto margin pushes to the end of the row, so the two controls stay
   together at every width and the language menu is always the last thing in
   the bar. */
.site-nav__controls {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 3rem;
  margin-inline-start: auto;
}

@media (min-width: 62rem) {
  .site-nav__links {
    order: 0;
    flex: 0 1 auto;
    height: auto;
    gap: 1.25rem;
    font-size: 0.9rem;
    margin-inline-start: auto;
    overflow-x: visible;
  }

  .site-nav {
    flex-wrap: nowrap;
    gap: 0 1.5rem;
    padding: 0 1.25rem;
  }

  .site-nav__brand,
  .site-nav__controls {
    height: auto;
  }

  .site-nav__controls {
    margin-inline-start: 0;
  }
}

/* The theme picker, injected by js/themes.js. Styled here rather than in
   themes.css because it is chrome, not a theme, and because it has to look
   right before a theme is chosen. */
.theme-picker {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: var(--gc-ink-muted);
}

/* The word is decoration next to an obvious control; below the nav's crowding
   point the select alone carries the meaning.  The select keeps an aria-label
   with the same word, set in js/themes.js, so hiding this costs nothing to a
   reader who is not looking at it. */
@media (max-width: 34rem) {
  .theme-picker__label {
    display: none;
  }

  /* A <select> is laid out to its widest option, and the widest thing in this
     one is an optgroup label ("Hot Dog Stand"), not the word on show.  Left
     uncapped it takes a third of a phone's bar for a word nobody is reading
     while the menu is shut. */
  .theme-picker__select {
    max-width: 8.5rem;
  }
}

.theme-picker__select {
  max-width: 11rem;
  padding: 0.2rem 0.4rem;
  background: var(--gc-page);
  color: var(--gc-ink);
  border: 1px solid var(--gc-hairline);
  border-radius: 6px;
  font: inherit;
  font-size: 0.85rem;
}

.theme-picker__select:focus-visible {
  outline: 2px solid var(--gc-accent);
  outline-offset: 1px;
}

/* -------------------------------------------------- the language menu */

/*
 * The language control at the top of the page, asked for because the footer
 * switcher is a long way down a long page.  It is a <details>, so it opens and
 * closes with no script at all: the CSP is script-src 'self' and the site is
 * readable with JavaScript off, and a language control that needed JavaScript
 * to open would be the one control a reader on the wrong language most needs.
 *
 * It carries the same seventeen anchors as the footer switcher, each in its
 * own language and script, each a real crawlable hreflang link.  The footer
 * one stays: it is where readers of static sites look, it needs no opening,
 * and it costs nothing to keep.
 */
.lang-menu__summary {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.5rem;
  background: var(--gc-page);
  color: var(--gc-ink-muted);
  border: 1px solid var(--gc-hairline);
  border-radius: 6px;
  font-size: 0.85rem;
  line-height: 1.5;
  cursor: pointer;
  /* The UA's own disclosure triangle, suppressed in both the forms browsers
     draw it in.  The chevron in the markup replaces it, and that one points
     the right way in Arabic without a second rule, because it is a rotated
     border rather than a glyph. */
  list-style: none;
}

.lang-menu__summary::-webkit-details-marker {
  display: none;
}

.lang-menu__summary:hover {
  color: var(--gc-ink);
  border-color: var(--gc-accent);
}

.lang-menu__summary:focus-visible {
  outline: 2px solid var(--gc-accent);
  outline-offset: 1px;
}

.lang-menu[open] .lang-menu__summary {
  color: var(--gc-ink);
  border-color: var(--gc-accent);
}

.lang-menu__globe {
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
}

/* The current language's own name, next to the globe.  It is the useful half
   of the button (it says where you are, not just what the button does), so it
   is the last thing dropped and only on the narrowest phones, where the globe
   plus the translated aria-label still carry it. */
@media (max-width: 30rem) {
  .lang-menu__current {
    display: none;
  }
}

.lang-menu__chevron {
  flex: none;
  width: 0.55rem;
  height: 0.55rem;
  margin-inline-start: 0.1rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
}

.lang-menu[open] .lang-menu__chevron {
  transform: translateY(0.1em) rotate(225deg);
}

/* Positioned against the BAR, not against the button: .site-nav is fixed and
   so is the containing block here.  That puts the panel below the whole
   header at both layouts, rather than half over the links row on a phone, and
   it lines the panel's edge up with the bar's own padding.  It hangs off the
   end of the bar, which is the right edge in English and the left edge in
   Arabic, so it opens inward and never off the screen. */
.lang-menu__panel {
  position: absolute;
  top: calc(100% + 0.4rem);
  inset-inline-end: 0.9rem;
  z-index: 30;
  width: max-content;
  min-width: 13rem;
  max-width: min(22rem, calc(100vw - 1.8rem));
  max-height: min(70vh, 24rem);
  overflow-y: auto;
  padding: 0.5rem;
  background: var(--gc-surface);
  border: 1px solid var(--gc-hairline);
  border-radius: 10px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.18);
}

.lang-menu__heading {
  margin: 0.1rem 0.35rem 0.4rem;
  font-size: 0.75rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--gc-ink-muted);
}

/* Two columns: seventeen entries in one column is a scroll on every phone,
   and in two it is nine rows that fit under the bar without one. */
.lang-menu__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.1rem 0.35rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.85rem;
}

/* The Arabic entry carries dir="rtl" so its own text is laid out with the
   right base direction, the same as in the footer switcher.  Left alone that
   would also align it to the right of its cell, out of step with the column
   it is in, so the alignment is taken from the list instead and the isolation
   kept: match-parent resolves against the list's direction, which is the
   page's. */
.lang-menu__list a {
  display: block;
  padding: 0.4rem 0.5rem;
  border-radius: 6px;
  color: var(--gc-ink);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: match-parent;
  unicode-bidi: isolate;
}

.lang-menu__list a:hover,
.lang-menu__list a:focus-visible {
  background: var(--gc-page);
  color: var(--gc-accent);
}

.lang-menu__list a[aria-current] {
  font-weight: 650;
  color: var(--gc-accent);
}

@media (min-width: 62rem) {
  .lang-menu__panel {
    inset-inline-end: 1.25rem;
  }
}

/* ------------------------------------------------------------ page frame */

#header,
#content,
#footnotes {
  max-width: var(--gc-measure);
  margin: 0 auto;
  padding: 0 1.25rem;
}

#header {
  padding-top: 3rem;
}

#header > h1 {
  margin: 0;
  font-size: 2.4rem;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

#header .details {
  margin: 0.75rem 0 0;
  color: var(--gc-ink-muted);
  font-size: 0.9rem;
}

/* The subtitle line an AsciiDoc doc-header can carry. */
#header .subtitle,
.doc-lede {
  color: var(--gc-ink-muted);
  font-size: 1.15rem;
  line-height: 1.5;
}

#content {
  padding-bottom: 4rem;
}

/* ------------------------------------------------------------------ toc */

#toc {
  margin: 2rem 0;
  padding: 1rem 1.25rem;
  background: var(--gc-surface);
  border: 1px solid var(--gc-hairline);
  border-radius: 10px;
}

#toc .title {
  margin: 0 0 0.5rem;
  font-weight: 650;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gc-ink-muted);
}

#toc ul {
  margin: 0;
  padding-left: 1.1rem;
  list-style: none;
}

#toc > ul {
  padding-left: 0;
}

#toc li {
  margin: 0.2rem 0;
}

#toc a {
  color: var(--gc-ink);
  text-decoration: none;
}

#toc a:hover {
  color: var(--gc-accent);
  text-decoration: underline;
}

/* A left-rail TOC on wide screens; it collapses back into the flow below. */
@media (min-width: 62rem) {
  body.toc2 {
    padding-left: 17rem;
  }

  body.toc2 #toc.toc2 {
    position: fixed;
    top: var(--gc-nav-height);
    left: 0;
    bottom: 0;
    width: 17rem;
    margin: 0;
    padding: 1.5rem 1.25rem;
    overflow-y: auto;
    background: var(--gc-surface);
    border: 0;
    border-right: 1px solid var(--gc-hairline);
    border-radius: 0;
  }
}

/* -------------------------------------------------------------- headings */

h1,
h2,
h3,
h4,
h5,
h6 {
  line-height: 1.25;
  letter-spacing: -0.015em;
  scroll-margin-top: calc(var(--gc-nav-height) + 1rem);
}

h2 {
  margin: 3rem 0 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--gc-hairline);
  font-size: 1.6rem;
}

h3 {
  margin: 2.25rem 0 0.75rem;
  font-size: 1.25rem;
}

h4,
h5,
h6 {
  margin: 1.75rem 0 0.5rem;
  font-size: 1.05rem;
}

/* Section anchors: present for linking, invisible until hover. */
h1 > a.anchor,
h2 > a.anchor,
h3 > a.anchor,
h4 > a.anchor,
h5 > a.anchor,
h6 > a.anchor {
  position: absolute;
  margin-left: -0.85em;
  width: 0.85em;
  opacity: 0;
  text-decoration: none;
  color: var(--gc-ink-muted);
}

h1 > a.anchor::before,
h2 > a.anchor::before,
h3 > a.anchor::before,
h4 > a.anchor::before,
h5 > a.anchor::before,
h6 > a.anchor::before {
  content: "\00A7";
}

h1:hover > a.anchor,
h2:hover > a.anchor,
h3:hover > a.anchor,
h4:hover > a.anchor,
h5:hover > a.anchor,
h6:hover > a.anchor,
a.anchor:focus {
  opacity: 1;
}

h1 > a.link,
h2 > a.link,
h3 > a.link,
h4 > a.link,
h5 > a.link,
h6 > a.link {
  color: inherit;
  text-decoration: none;
}

/* ------------------------------------------------------------ body text */

p,
ul,
ol,
dl {
  margin: 0 0 1rem;
}

ul,
ol {
  padding-left: 1.4rem;
}

li > p {
  margin-bottom: 0.5rem;
}

dt {
  margin-top: 1rem;
  font-weight: 650;
}

dd {
  margin: 0.25rem 0 0 1.25rem;
}

blockquote,
.quoteblock blockquote {
  margin: 1.5rem 0;
  padding: 0.25rem 0 0.25rem 1.25rem;
  border-left: 3px solid var(--gc-hairline);
  color: var(--gc-ink-muted);
}

.quoteblock .attribution {
  font-size: 0.9rem;
}

hr {
  margin: 2.5rem 0;
  border: 0;
  border-top: 1px solid var(--gc-hairline);
}

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

code,
kbd,
pre {
  font-family: var(--gc-font-mono);
  font-size: 0.875em;
}

:not(pre) > code {
  padding: 0.15em 0.35em;
  background: var(--gc-code-bg);
  border-radius: 4px;
}

kbd {
  padding: 0.1em 0.4em;
  background: var(--gc-surface);
  border: 1px solid var(--gc-hairline);
  border-bottom-width: 2px;
  border-radius: 4px;
  white-space: nowrap;
}

.listingblock,
.literalblock {
  margin: 1.5rem 0;
}

.listingblock pre,
.literalblock pre {
  margin: 0;
  padding: 1rem 1.15rem;
  overflow-x: auto;
  background: var(--gc-surface);
  border: 1px solid var(--gc-hairline);
  border-radius: 10px;
  line-height: 1.55;
}

.title {
  margin-bottom: 0.4rem;
  font-size: 0.9rem;
  font-style: italic;
  color: var(--gc-ink-muted);
}

/* ----------------------------------------------------------- admonitions */

.admonitionblock {
  margin: 1.5rem 0;
}

.admonitionblock > table {
  width: 100%;
  border: 1px solid var(--gc-hairline);
  border-left: 4px solid var(--gc-accent-bright);
  border-radius: 10px;
  border-collapse: separate;
  background: var(--gc-surface);
}

.admonitionblock td {
  padding: 0.9rem 1.1rem;
  vertical-align: top;
  border: 0;
}

.admonitionblock td.icon {
  width: 1px;
  padding-right: 0;
  white-space: nowrap;
}

.admonitionblock td.icon .title {
  margin: 0;
  font-style: normal;
  font-weight: 650;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gc-accent);
}

.admonitionblock td.content > :last-child {
  margin-bottom: 0;
}

.admonitionblock.warning > table,
.admonitionblock.caution > table {
  border-left-color: #d0521b;
}

.admonitionblock.warning td.icon .title,
.admonitionblock.caution td.icon .title {
  color: #d0521b;
}

/* ---------------------------------------------------------------- tables */

table.tableblock {
  width: 100%;
  margin: 1.5rem 0;
  border-collapse: collapse;
  font-size: 0.95rem;
}

table.tableblock caption {
  margin-bottom: 0.4rem;
  text-align: left;
  font-style: italic;
  color: var(--gc-ink-muted);
}

th.tableblock,
td.tableblock {
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--gc-hairline);
  text-align: left;
  vertical-align: top;
}

thead th.tableblock {
  border-bottom-width: 2px;
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--gc-ink-muted);
}

td.tableblock > .paragraph:last-child > p {
  margin-bottom: 0;
}

/* Wide tables scroll inside their own box rather than the page. */
.tableblock-scroll {
  overflow-x: auto;
}

/* ---------------------------------------------------------- wireframes */

/*
 * Screen wireframes are generated from the real Flutter widget tree (see
 * WIREFRAMES.adoc), so they are phone-shaped and quite tall. Constrain them to
 * a plausible device width and give them a device-ish frame; left-floating
 * them next to the prose is what makes a walkthrough readable.
 */
.imageblock.wireframe {
  margin: 1.5rem 0;
}

.imageblock.wireframe img {
  display: block;
  width: 100%;
  max-width: 320px;
  border: 1px solid var(--gc-hairline);
  border-radius: 18px;
  background: #fff;
  /* Legitimate only because the image carries no hue: a monochrome render
     inverts to a readable dark-mode wireframe, where a colour screenshot would
     come out as a lie. The border inverts with it, which is what keeps the
     hairline a hairline. */
  filter: invert(var(--gc-wf-invert, 0));
}

.imageblock.wireframe .title {
  max-width: 320px;
  margin-top: 0.5rem;
  text-align: center;
}

@media (min-width: 48rem) {
  .imageblock.wireframe.left {
    float: left;
    margin: 0.5rem 1.75rem 1rem 0;
  }

  .imageblock.wireframe.right {
    float: right;
    margin: 0.5rem 0 1rem 1.75rem;
  }
}

/* A section that floats a wireframe must not let it bleed into the next. */
.sect2,
.sect3 {
  overflow: hidden;
}

/* Side-by-side wireframes for state comparisons. */
.wireframe-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  margin: 1.5rem 0;
}

.wireframe-row .imageblock.wireframe {
  flex: 0 1 220px;
  margin: 0;
}

/* ------------------------------------------------------------- footnotes */

#footnotes {
  padding-top: 1.5rem;
  border-top: 1px solid var(--gc-hairline);
  font-size: 0.9rem;
  color: var(--gc-ink-muted);
}

/* ----------------------------------------------------------- site footer */

.site-footer {
  padding: 2rem 1.25rem 3rem;
  border-top: 1px solid var(--gc-hairline);
  background: var(--gc-surface);
  text-align: center;
  font-size: 0.9rem;
  color: var(--gc-ink-muted);
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.25rem;
  margin: 0 0 0.75rem;
  padding: 0;
  list-style: none;
}

.site-footer__links a {
  color: var(--gc-ink-muted);
  text-decoration: none;
}

.site-footer__links a:hover {
  color: var(--gc-accent);
  text-decoration: underline;
}

.site-footer__legal {
  margin: 0;
}

/* The language switcher (docinfo-footer.html).  Sixteen short links, wrapped
   and centred like the footer links above, but a step quieter: it is a way
   out for the reader on the wrong page, not a destination. */
.lang-switcher {
  margin-top: 1.25rem;
}

.lang-switcher__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.85rem;
}

.lang-switcher__list a {
  color: var(--gc-ink-muted);
  text-decoration: none;
}

.lang-switcher__list a:hover {
  color: var(--gc-accent);
  text-decoration: underline;
}

/* The build stamp: which version this page is, when it was built, and from which commit.  Three
   lines with room around them, because run together on one line they read as a single unfamiliar
   string rather than three facts a reader can use.  Tabular figures so the version and the
   timestamp line up rather than wobbling. */
.build-stamp {
  display: inline-block;
  margin: 1.5rem 0 0;
  padding: 0.7rem 1.1rem;
  background: var(--gc-page);
  border: 1px solid var(--gc-hairline);
  border-radius: 8px;
  font-size: 0.8rem;
  line-height: 1.7;
  text-align: left;
  font-variant-numeric: tabular-nums;
  color: var(--gc-ink-muted);
}

.build-stamp__row {
  display: block;
}

.build-stamp code {
  padding: 0.05em 0.3em;
  background: var(--gc-code-bg);
  border-radius: 4px;
  font-size: 0.95em;
  color: var(--gc-ink);
}

/* ------------------------------------------------------------- utilities */

.text-center {
  text-align: center;
}

/* A landing-page grid of cards, used by index.adoc. */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
  margin: 2rem 0;
}

/* Asciidoctor wraps an open block's children in a .content div, so the cards
   are grandchildren of .card-grid rather than children.  Without this the grid
   has exactly one item, the wrapper, and every rule below matches nothing:
   which is why these cards rendered as bare paragraphs from the first commit
   until 2026-08-11.  display:contents drops the wrapper out of the box tree
   and lets the cards be the grid items. */
.card-grid > .content {
  display: contents;
}

.card-grid .card {
  padding: 1.15rem 1.3rem;
  background: var(--gc-surface);
  border: 1px solid var(--gc-hairline);
  border-radius: 12px;
}

/* A card's heading is a block title, so it has to override the global .title
   rule, which is small, italic and muted because it is written for a figure
   caption. */
.card-grid .card > .title {
  margin: 0 0 0.4rem;
  font-size: 1.05rem;
  font-weight: 650;
  font-style: normal;
  color: var(--gc-ink);
}

.card-grid .card > .title a {
  text-decoration: none;
}

.card-grid .card > .title a:hover {
  text-decoration: underline;
}

.card-grid .card p {
  margin: 0;
  font-size: 0.95rem;
  color: var(--gc-ink-muted);
}

@media print {
  .site-nav,
  .site-footer,
  #toc {
    display: none;
  }

  body {
    padding: 0;
  }
}

/*
 * Chromeless / embedded mode. When a page is framed inside the Grilled Cheese
 * app's About screen (opened with ?embed=1), the app supplies its own title
 * bar and theme, so the site nav, the document header (title + revision line),
 * and the footer are all out of place. Hide them and reclaim the space the
 * fixed nav reserved. The class is set on <html> before the first paint by
 * js/embed.js, so nothing flashes.
 */
html.gc-embed .site-nav,
html.gc-embed .site-footer,
html.gc-embed #header,
html.gc-embed #toc {
  display: none;
}

html.gc-embed body {
  padding-top: 0;
}
