/* The demo's own styling: layout only. The glass is vitral's, which ships with
   the gem, and this page uses its public classes (vitral-pane, vitral-panes,
   vitral-button) and its custom properties rather than restating any of it.
   That is the arrangement a host is meant to copy. */

* { box-sizing: border-box; }

/* The gallery's renderer links are in-page jumps to a section id, and this is
   the one property that makes the browser glide there instead of cutting.
   Reduced motion turns it back to the instant jump below, because for
   someone who asked for less motion that jump is the correct behaviour, not
   a fallback. */
html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.5;
}

nav {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  gap: 1.5rem;
  align-items: baseline;
  padding: .85rem 1.25rem;
  background: var(--vitral-glass-strong);
  -webkit-backdrop-filter: var(--vitral-blur);
  backdrop-filter: var(--vitral-blur);
  border-bottom: 1px solid var(--vitral-came-soft);
}
nav a { color: var(--vitral-muted); text-decoration: none; font-size: .95rem; }
/* Aligned on the text baseline rather than on box centres: the brand is a
   larger font than the links, so centring their boxes left the words about a
   pixel apart. An inline brand gives the row its baseline from the word
   Janela, and the mark is centred on that line instead of setting it. */
nav .brand { display: inline; color: var(--vitral-ink); white-space: nowrap;
             font-weight: 650; letter-spacing: -0.01em; font-size: 1.05rem; }
nav .brand .brand-mark { display: inline-block; vertical-align: -0.42em; margin-right: .55rem; }
.brand-mark { display: block; filter: drop-shadow(0 1px 1px rgba(16, 24, 40, .18)); }
nav a:hover { color: rgb(25, 112, 176); }

/* The hamburger button. Plain CSS bars rather than a character or an image,
   so it never waits on a font and never needs an asset. */
.nav-toggle {
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  list-style: none;
}
.nav-toggle::-webkit-details-marker { display: none; }
/* Three bars from one pseudo-element: the middle bar plus a shadow cast above
   and below it, rather than three separate elements for one static icon. */
.nav-toggle::before {
  content: "";
  width: 1.35rem;
  height: 2px;
  background: var(--vitral-ink);
  box-shadow: 0 -.4rem 0 var(--vitral-ink), 0 .4rem 0 var(--vitral-ink);
}

/* Its own flex row, pushed to the far right by the auto margin, so the brand
   and the links anchor the two ends of the bar instead of sitting side by
   side at the left. The hamburger's copy of the same links stays out of the
   layout entirely. */
.nav-links-wide { display: flex; align-items: baseline; gap: 1.5rem; margin-left: auto; }
.nav-menu { display: none; }

@media (max-width: 40rem) {
  .nav-links-wide { display: none; }

  nav {
    display: grid;
    grid-template-columns: 2.75rem 1fr 2.75rem;
    /* Sparse packing (the default) walks items in DOM order and never moves
       the placement cursor backward: the brand comes first and claims column
       2, which pushes its cursor past column 1, so the hamburger after it in
       the DOM (column 1) misses row 1 entirely and falls to row 2. Dense
       packing is allowed to fill that earlier gap instead. */
    grid-auto-flow: dense;
    align-items: center;
    gap: 0;
  }
  nav .brand { grid-column: 2; justify-self: center; }
  .nav-menu { display: block; grid-column: 1; }
  .nav-toggle { display: inline-flex; }
  /* The dropdown hangs off the nav itself: `position: sticky` already makes
     nav a containing block, so this needs nothing extra to anchor to it. */
  .nav-menu .nav-links {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: grid;
    gap: 0;
    /* Opaque, not the nav bar's own translucent glass: this panel overlays
       whatever the page put there, including a dashboard's coloured panes,
       and glass over that reads as smudged rather than readable. The site's
       own ground colour keeps it one surface with the rest of the page while
       still reading as elevated, via the same shadow a vitral pane lifts on. */
    background: var(--vitral-ground);
    border-bottom: 1px solid var(--vitral-came-soft);
    box-shadow: var(--vitral-shadow);
  }
  /* A full width row with real padding, so a thumb does not have to aim. */
  .nav-menu .nav-links a { padding: 1rem 1.25rem; text-align: center; }

  /* Each entry is assigned one of the theme's pane colours in order, the
     same stack the mark and the footer leading are cut from, but at rest
     that colour stays unused: the row sits plain on the panel's own ground,
     so the menu reads as quiet and ordinary until something is touched. */
  .nav-menu .nav-links a:nth-child(5n + 1) { --pane: var(--vitral-pane-1); }
  .nav-menu .nav-links a:nth-child(5n + 2) { --pane: var(--vitral-pane-2); }
  .nav-menu .nav-links a:nth-child(5n + 3) { --pane: var(--vitral-pane-3); }
  .nav-menu .nav-links a:nth-child(5n + 4) { --pane: var(--vitral-pane-4); }
  .nav-menu .nav-links a:nth-child(5n + 5) { --pane: var(--vitral-pane-5); }
  .nav-menu .nav-links a {
    transition: background-color .15s ease, color .15s ease;
  }
  /* Only the entry under the pointer or the thumb takes its pane colour, and
     only a single layer of it (the panes are already translucent) rather
     than the doubled-up, brighter wash an earlier pass used here: one layer
     reads as glass catching the light, two read as a coloured button. Ink
     replaces the usual blue link hover here instead of sitting on top of it:
     checked against the lit background, that blue drops to 2.3:1 on pane 1,
     where ink clears 7:1 on all five, and a single layer is only lighter
     than that. Both states get it, hover for a pointer and active for the
     thumb that is actually here on a phone: gating hover behind a
     capability query left the unrelated global `nav a:hover` blue free to
     win instead whenever a device fired :hover without matching the query,
     which is the same low-contrast text this is meant to avoid. */
  .nav-menu .nav-links a:hover,
  .nav-menu .nav-links a:active {
    background: var(--pane);
    color: var(--vitral-ink);
  }
}

/* While the menu is open, the page behind it stays put: no script, no fixed
   positioning that would reset scroll, just the one rule the open attribute
   already gives us something to select on. */
body:has(.nav-menu[open]) { overflow: hidden; }

.hero, .live, .why, .features, .code, .fork, .faq,
.demo-header, .demo-footer, .demo-toolbar, .demo-grid, .demo-frame,
.frame-page {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 1.25rem;
}

.hero { padding-bottom: .5rem; }
/* The window itself, above the words, where the light from the top right
   catches it. */
/* The glow lives on a wrapper as a plain gradient rather than on the mark as
   a filter. Transitioning a filter on an SVG rasterises the whole thing every
   frame, which is what made the hover feel like it was stuttering. */
.hero-mark-wrap {
  position: relative;
  display: block;
  width: fit-content;
  margin: 0 auto 1.5rem;
}
.hero-mark-wrap::before {
  content: "";
  position: absolute;
  inset: -28%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 243, 214, 0.9), rgba(255, 246, 226, 0.35) 55%, transparent 72%);
  opacity: 0;
  transition: opacity .55s ease;
  pointer-events: none;
}
.hero-mark-wrap:hover::before { opacity: 1; }
.hero-mark { display: block; filter: drop-shadow(0 6px 14px rgba(16, 24, 40, 0.18)); }
.hero h1 {
  margin: 0 0 1rem;
  font-size: clamp(2.1rem, 5vw, 3.4rem);
  line-height: 1.08;
  letter-spacing: -0.03em;
  background: linear-gradient(115deg, var(--vitral-ink) 18%, rgb(25, 112, 176) 52%, rgb(120, 86, 200) 78%, rgb(186, 106, 72));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.hero-sub { font-size: 1.2rem; line-height: 1.55; color: var(--vitral-muted); max-width: 58ch; margin: 0 0 1.75rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; margin: 0 0 1rem; }
.hero-actions[hidden] { display: none; }
.hero-note { color: var(--vitral-muted); font-size: .95rem; }

.live, .why, .features, .code, .fork, .faq { padding-top: 3rem; padding-bottom: .5rem; }
.live h2, .why h2, .features h2, .code h2, .fork h2, .faq h2 {
  font-size: 1.65rem; margin: 0 0 .5rem; letter-spacing: -0.02em;
}
.lede { color: var(--vitral-muted); line-height: 1.65; max-width: 70ch; }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .9em;
  background: rgba(255, 255, 255, 0.6);
  border: 1px solid var(--vitral-came-soft);
  border-radius: 6px;
  padding: .1rem .35rem;
}

.demo-frame { margin-top: 1.25rem; margin-bottom: 1.25rem; }
.demo-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; padding-bottom: 2rem; }
.demo-grid-3 { grid-template-columns: repeat(3, 1fr); padding-left: 0; padding-right: 0; }
.demo-grid-4 { grid-template-columns: repeat(4, 1fr); padding-left: 0; padding-right: 0; }
.demo-tile { padding: 1.15rem 1.25rem; min-height: 5rem; }
.demo-wide { grid-column: span 3; }
.demo-grid-4 .demo-wide { grid-column: span 4; }
.demo-toolbar { margin: 1rem auto; }

.demo-header { padding-top: 2.5rem; }
.demo-header h1 { margin: 0 0 .5rem; font-size: 2rem; letter-spacing: -0.02em; }
.demo-header p { color: var(--vitral-muted); line-height: 1.6; max-width: 70ch; }

/* Janela's own pages (Frames) carry a bare h1 straight into .frame-page, with
   no header element of their own to hold the top padding a page like this
   one gets from .demo-header instead. Same value, so the heading sits the
   same distance under the nav either way. */
.frame-page { padding-top: 2.5rem; }

/* A small caps label, used above a page heading as a category eyebrow and
   above a group of sidebar entries alike: one rule for both, the way the
   gallery's own declaration label already looked. */
.eyebrow {
  margin: 0 0 .5rem;
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--vitral-muted);
}

/* The shell: the shape shared by every reference page in this demo, the
   gallery and the documentation alike, so there is one of these rather than
   two that look alike. It reads as a documentation site (Tailwind's own docs
   are the model): a navigation flush to the window's left edge, full height
   below the top bar, and a wide content column beside it rather than a
   narrow centred measure. Full bleed on purpose, so it opts out of the
   site's shared centred-container rule instead of sitting inside it, and
   carries no max-width of its own either: a cap just moves the same banding
   to whatever monitor is wider than it, it does not remove it. The sidebar's
   own width is fixed (18rem) and the content column is `minmax(0, 1fr)`, so
   the sidebar sits at the window's left edge and the content fills to its
   right edge at any width, with each column's own padding doing the
   spacing. 18rem rather than the original 16rem: at 16 an ordinary entry
   ("Naming Things Is Hard", since moved out of this nav onto its own page)
   wrapped onto two lines, and the fix is a sidebar wide enough for one line,
   not a nav trimmed for a narrower one. */
.shell {
  display: grid;
  grid-template-columns: 18rem minmax(0, 1fr);
  align-items: start;
}
/* A grid item's default min-width is auto, which floors it at its content's
   own min-content size: the gallery's one-line declaration is pre-formatted
   and will not wrap, so without this every ancestor grid stretches to fit it
   instead of letting its own overflow-x scroll the code, and the whole page
   grows wider than a phone. */
.shell > * { min-width: 0; }

/* Pinned under the site nav and running its own full height beneath it,
   scrolling on its own once its list outgrows the viewport rather than
   pushing the page taller than the content beside it. A hairline came
   marks it off from the content column; no fill, no card, because this is a
   navigation rather than a panel. */
.shell-nav {
  /* The site nav's own `nav { display: flex; align-items: baseline; gap:
     1.5rem; background: var(--vitral-glass-strong); ...; border-bottom: 1px
     solid var(--vitral-came-soft); }` (further up this file) targets every
     `<nav>`, this one included, and this selector never named its own
     display, background or border: the eyebrow and the list were falling
     into that flex row as two side-by-side items instead of stacking, and
     the glass fill plus a bottom edge on top of this rule's own right-hand
     hairline made the sidebar read as a panel sitting on the page rather
     than sharing it. Every one of those is this nav's own layout and
     surface, not a patch on top of the leaked one: no blur, no border but
     the single hairline on the right that actually separates it from the
     content, because this is a navigation rather than a panel. Plain white
     rather than the page's own tinted ground, so it reads as its own
     surface next to the lattice now showing behind the content beside it. */
  display: block;
  position: sticky;
  /* 4.5rem overshot the top bar's own rendered height (it settles at
     ~54px, not 72px, once the system font stack lays out the baseline row),
     which held this sticky box 18px below the bar instead of flush under
     it, at rest as well as while scrolling: a sticky box never renders
     above its own `top`, so the gap was there from first paint, not just
     once scrolling engaged it. 3.4rem matches the bar as it actually
     renders. */
  top: 3.4rem;
  height: calc(100vh - 3.4rem);
  overflow-y: auto;
  background: #fff;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  /* Left padding matches the top bar's own 1.25rem so the eyebrow lines up
     under the brand instead of sitting 4px further from the window edge. */
  padding: 2.5rem 1.5rem 2rem 1.25rem;
  border-bottom: 0;
  border-right: 1px solid var(--vitral-came-soft);
}
.shell-nav-group + .shell-nav-group { margin-top: 2rem; }
.shell-nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
.shell-nav a {
  display: block;
  padding: .4rem .75rem .4rem .9rem;
  border-left: 2px solid transparent;
  font-size: .92rem;
  font-weight: 550;
  text-decoration: none;
  color: var(--vitral-muted);
}
.shell-nav a:hover { color: var(--vitral-ink); }
/* The page a reader is on is marked the same way in both groups, but by two
   different means. A Documentation link is its own page, so the server
   knows which one is current and says so with a class. A Reference link is
   an in-page jump on the gallery rather than a page of its own, so which one
   is current is asked of the browser instead: :target on the section itself,
   read back onto its own link via :has(), needs no script to track it. Four
   sections, four rules, because :has() cannot ask a stylesheet's own
   variables which ids exist. */
.shell-nav a.current,
.shell:has(#gallery-table:target) .shell-nav a[href$="#gallery-table"],
.shell:has(#gallery-bar:target) .shell-nav a[href$="#gallery-bar"],
.shell:has(#gallery-line:target) .shell-nav a[href$="#gallery-line"],
.shell:has(#gallery-combo:target) .shell-nav a[href$="#gallery-combo"] {
  border-left-color: var(--janela-accent);
  color: var(--vitral-ink);
  font-weight: 650;
}

/* A query container, not just a grid item: the footer nested in here (see
   shared/_footer) has its own fixed-width columns sized for the site's usual
   1100px-wide slot, and this column is narrower than that whenever the
   sidebar is showing. Viewport-width media queries cannot see that the
   sidebar ate 16rem; only asking this column its own width can. */
.shell-main { container-type: inline-size; }
.shell-content { padding: 2.5rem 2.5rem 0 2.5rem; }

.gallery-header { margin-bottom: 2.5rem; }
.gallery-header h1 { margin: .35rem 0 .75rem; font-size: 2rem; letter-spacing: -0.02em; }
.gallery-header p { color: var(--vitral-muted); line-height: 1.6; max-width: 70ch; }

.gallery-section { margin-bottom: 3rem; scroll-margin-top: 4.5rem; }
.gallery-section:last-child { margin-bottom: 0; }
.gallery-section h2 { font-size: 1.5rem; margin: 0 0 .4rem; letter-spacing: -0.02em; }
.gallery-section .lede { margin: 0 0 1.5rem; }

/* The declaration and chart beside it already sit on their own glass
   (.vitral-pane), so the lattice returning to full strength behind the
   gallery never touches their legibility. This heading and lede prose is
   the one thing in the column with no pane of its own, so each gets a soft
   knockout in the page's own ground colour instead: a halo behind the
   glyphs rather than a card around the paragraph, so the reading column
   stays bare the way the sidebar and the rest of this file's headings do,
   and only the letterforms themselves get the contrast. */
.gallery-header .eyebrow, .gallery-header h1, .gallery-header p,
.gallery-section h2, .gallery-section .lede {
  text-shadow: 0 0 4px var(--vitral-ground), 0 0 10px var(--vitral-ground), 0 0 18px var(--vitral-ground);
}

.gallery-entry { margin-top: 1.75rem; }
.gallery-entry:first-of-type { margin-top: 0; }
.gallery-entry h3 { margin: 0 0 .75rem; font-size: 1.05rem; letter-spacing: -0.01em; }

.gallery-entry-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; align-items: start; }
.gallery-entry-grid > * { min-width: 0; }
.gallery-visual, .gallery-code { padding: 1.15rem 1.25rem; }

.gallery-declaration { display: block; white-space: normal; overflow-wrap: break-word; }

/* Beside the declaration it updates, not a form of its own on the page: no
   max-width, no submit, gap tightened from .janela-form's default so it
   reads as part of this card rather than a login form dropped into it (#40). */
.gallery-note { margin: 1rem 0 0; font-size: .9rem; line-height: 1.5; color: var(--vitral-muted); }
.gallery-config-form { margin: 1rem 0 0; max-width: none; gap: .6rem; }
.gallery-config-form .janela-field { gap: .2rem; }
.gallery-config-form [hidden] { display: none; }
.gallery-config-form .gallery-check { flex-direction: row; justify-content: flex-start; align-items: center; gap: .5rem; }
.gallery-config-form .gallery-check label { margin: 0; }
.gallery-companions { border: 0; padding: 0; margin: 0; display: grid; gap: .3rem; }
.gallery-companions legend { padding: 0; font-weight: 600; margin-bottom: .2rem; }

@media (max-width: 52rem) {
  .shell { display: block; }
  .shell-nav { display: none; }
  .shell-content { padding: 2rem 1.25rem 0; }
  .gallery-entry-grid { grid-template-columns: 1fr; }
}

.reasons { list-style: none; padding: 0; display: grid; gap: .85rem; max-width: 70ch; }
.reasons li { line-height: 1.65; color: var(--vitral-muted); }
.reasons strong { color: var(--vitral-ink); }

.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-top: 1.25rem; }
.card { padding: 1.2rem 1.3rem; }
.card h3 { margin: 0 0 .4rem; font-size: 1.05rem; letter-spacing: -0.01em; }
.card p { margin: 0; color: var(--vitral-muted); line-height: 1.55; font-size: .95rem; }


.qa-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; margin-top: 1.25rem; }
.qa { padding: 1.2rem 1.3rem; }
.qa h3 { margin: 0 0 .4rem; font-size: 1.02rem; letter-spacing: -0.01em; }
.qa p { margin: 0; color: var(--vitral-muted); line-height: 1.6; font-size: .95rem; }

/* Each pane of the mark answers on its own, because the point being made is
   that this is glass rather than a picture of glass: it lights up, it lifts,
   and the window's own leading clips it as it moves. */
.brand-mark .pane, .hero-mark .pane, .footer-mark .pane {
  fill-opacity: .85;
  transform-box: fill-box;
  transform-origin: center;
  will-change: transform;
  transition: fill-opacity .45s ease, transform .5s cubic-bezier(.22, .68, .3, 1);
}
.brand-mark .pane:hover, .hero-mark .pane:hover, .footer-mark .pane:hover {
  fill-opacity: 1;
  transform: scale(1.05);
}
/* Light through the back of the window, splitting into its colours as it
   comes out the front, opening like a fan. At rest every ray is folded back
   to straight down and short; on hover each swings out to its own angle, a
   beat after the one before it. Only the large mark: at nav size the rays
   would be a smudge over the words beside it. */
.hero-mark { overflow: visible; }
.hero-mark .rays .ray {
  transform-box: view-box;
  transform-origin: 16px 19px;
  transform: rotate(calc(var(--angle) * -1)) scaleY(0.3);
  opacity: 0;
  transition: transform 1.2s cubic-bezier(.16, .84, .3, 1), opacity .8s ease;
}
.hero-mark-wrap:hover .rays .ray {
  transform: rotate(0deg) scaleY(1);
  opacity: 1;
  transition-delay: calc(var(--ray) * 80ms);
}
.brand-mark .rays, .footer-mark .rays { display: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .brand-mark .pane, .hero-mark .pane, .footer-mark .pane { transition: fill-opacity .2s ease; }
  .brand-mark .pane:hover, .hero-mark .pane:hover, .footer-mark .pane:hover { transform: none; }
  .hero-mark .rays .ray { transition: opacity .3s ease; transform: rotate(0deg); }
  .hero-mark-wrap:hover .rays .ray { transform: rotate(0deg); }
  .nav-menu .nav-links a { transition: none; }
}

/* The bottom pane of the window: full bleed glass, the five colours as its
   leading, and the same light crossing it. Built from vitral's own properties
   rather than its classes, because it wants no corners and no max width. */
.site-footer {
  position: relative;
  margin-top: 5rem;
  padding: 3.5rem 0 2.5rem;
  background: linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.62));
  -webkit-backdrop-filter: var(--vitral-blur);
  backdrop-filter: var(--vitral-blur);
  border-top: 1px solid var(--vitral-came-soft);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
}

/* The leading, in the glass colours, read left to right like the mark. */
.site-footer::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: linear-gradient(90deg,
    var(--vitral-pane-1) 0 20%, var(--vitral-pane-2) 20% 40%, var(--vitral-pane-3) 40% 60%,
    var(--vitral-pane-4) 60% 80%, var(--vitral-pane-5) 80% 100%);
  opacity: 0.9;
}

/* Brand on the left, the three link groups spread to the right edge. A flex
   row let everything huddle at the left and left half the band empty. */
.site-footer-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 1.25rem;
  display: grid;
  grid-template-columns: minmax(18rem, 30rem) repeat(3, minmax(7rem, 1fr));
  gap: 2.5rem 2.5rem;
  align-items: start;
}
/* The wrapper stays in the markup and steps out of the grid, so each group is
   a column of its own. */
.footer-links { display: contents; }

.footer-brand { display: flex; gap: 1.35rem; align-items: flex-start; max-width: 36rem; }
.footer-mark { flex: none; filter: drop-shadow(0 4px 10px rgba(16, 24, 40, 0.16)); }
.footer-name { margin: 0 0 .45rem; font-weight: 650; letter-spacing: -0.01em; font-size: 1.05rem; }
.footer-tag { margin: 0; color: var(--vitral-muted); line-height: 1.6; font-size: .92rem; }
.footer-tag em { font-style: italic; }

.footer-links h2 {
  margin: 0 0 .6rem;
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--vitral-muted);
}
.footer-links ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem; }
.footer-links a { text-decoration: none; font-size: .92rem; }
/* The gem's numbers as a row of badges under the heading, the way a README
   shows them: the column is too narrow to set one beside its link. */
.footer-stats { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0 0 .85rem; }
.footer-links a.footer-stat {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .2rem .65rem; border-radius: 999px;
  font-size: .76rem; font-variant-numeric: tabular-nums; white-space: nowrap;
  color: var(--vitral-ink); text-decoration: none;
  background: rgb(255 255 255 / .62); border: 1px solid rgb(16 24 40 / .12);
}
.footer-links a.footer-stat:hover { background: rgb(255 255 255 / .9); text-decoration: none; }
.footer-stat-stars::before { content: "\2605"; color: #d99a1c; }
.footer-stat-downloads::before { content: "\2193"; color: var(--vitral-muted); }
.footer-links a:hover { text-decoration: underline; }

/* Documentation. The prose sits on a pane of glass like everything else, but
   wider measure and quieter, because this is the reading surface. Both pages
   live in .shell-content now, which already supplies the top and side
   padding a bare page used to need from these rules, so neither repeats it. */
.doc-head, .doc-list { max-width: 1100px; margin: 0 auto; }
/* One document reads at a book's measure, so the glass hugs the prose rather
   than standing a page's width behind it: the prose's 74ch plus the pane's
   padding and border, so a paragraph runs edge to edge inside the glass. */
.doc { max-width: calc(74ch + 4.5rem + 2px); margin: 0 auto; }
.doc .doc-head { max-width: none; }
.doc-head h1 { margin: 0 0 .75rem; font-size: clamp(1.9rem, 4vw, 2.6rem); letter-spacing: -0.03em; line-height: 1.1; }
.doc-list { padding-top: 2.5rem; }
/* The sidebar's "Every decision" link is an in-page jump here, not a page of
   its own, so it needs the same clearance under the sticky top bar that
   .shell-nav gives itself against the same bar (3.4rem, see its own rule
   above), or the heading lands half hidden behind it on arrival. */
#decisions { scroll-margin-top: 3.4rem; }
.doc-list h2 { font-size: 1.5rem; margin: 0 0 .6rem; letter-spacing: -0.02em; }

.doc-cards { list-style: none; margin: 1.25rem 0 0; padding: 0; display: grid;
             grid-template-columns: repeat(2, 1fr); gap: 1rem; }
.doc-card { padding: 1.15rem 1.3rem; }
.doc-card a { font-weight: 600; text-decoration: none; }
.doc-card a:hover { text-decoration: underline; }
.doc-topics { margin: .4rem 0 0; color: var(--vitral-muted); font-size: .82rem; }

.doc-index { list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: .1rem; }
.doc-index li {
  display: grid;
  grid-template-columns: 2.5rem 1fr auto;
  gap: 1rem;
  align-items: baseline;
  padding: .7rem .9rem;
  border-radius: 8px;
}
.doc-index li:hover { background: rgba(255, 255, 255, 0.5); }
.doc-number { color: var(--vitral-muted); font-variant-numeric: tabular-nums; font-size: .85rem; }
.doc-title { text-decoration: none; font-weight: 550; }
.doc-title:hover { text-decoration: underline; }
.doc-meta { color: var(--vitral-muted); font-size: .8rem; display: inline-flex; gap: .7rem; align-items: center; }
.doc-status {
  text-transform: uppercase; letter-spacing: .07em; font-size: .66rem; font-weight: 650;
  padding: .12rem .45rem; border-radius: 999px; border: 1px solid var(--vitral-came-soft);
}
.doc-status-accepted { color: rgb(20, 116, 104); background: rgba(28, 168, 158, 0.16); }
.doc-status-proposed { color: rgb(150, 104, 20); background: rgba(240, 176, 70, 0.2); }
.doc-status-superseded { color: var(--vitral-muted); }

.doc-crumb { margin: 0 0 1.25rem; font-size: .88rem; display: flex; gap: 1.25rem; }
.doc-crumb-end { margin: 1.75rem 0 0; }
.doc-prose { padding: 2rem 2.25rem; }
.doc-prose > :first-child { margin-top: 0; }
.doc-prose > :last-child { margin-bottom: 0; }
.doc-prose h2 { font-size: 1.32rem; margin: 2rem 0 .6rem; letter-spacing: -0.02em; }
.doc-prose h3 { font-size: 1.05rem; margin: 1.5rem 0 .5rem; }
.doc-prose p, .doc-prose li { line-height: 1.7; max-width: 74ch; }
.doc-prose li { margin: .3rem 0; }
.doc-prose strong { font-weight: 650; }
.doc-prose pre {
  background: rgba(255, 255, 255, 0.62);
  border: 1px solid var(--vitral-came-soft);
  border-radius: 10px;
  padding: 1rem 1.15rem;
  overflow-x: auto;
  line-height: 1.55;
}
.doc-prose pre code { background: none; border: 0; padding: 0; font-size: .85rem; }
.doc-prose table { border-collapse: separate; border-spacing: 0; width: 100%; margin: 1.25rem 0; font-size: .92rem; }
.doc-prose th, .doc-prose td { text-align: left; padding: .55rem .7rem; border-bottom: 1px solid var(--vitral-came-soft); vertical-align: top; }
.doc-prose th { font-size: .72rem; text-transform: uppercase; letter-spacing: .07em; color: var(--vitral-muted); }
/* A long word in a narrow column sets a table's minimum width, and a table that
   cannot shrink below it pushes the whole page sideways: "Horizonte" in the
   naming table's first column widened that table by 26px, which fits a phone
   here and measured 405px against 390px on CI, where the fallback font is about
   a quarter wider than the one installed locally. Letting the cells break words
   instead collapses the narrow column to roughly one character per line, so the
   table scrolls inside its own box and the page does not. Doc#html is what puts
   the box there, since the markdown renderer emits a bare table. */
.doc-table { overflow-x: auto; margin: 1.25rem 0; }
.doc-table table { margin: 0; width: auto; min-width: 100%; }

.doc-prose blockquote {
  margin: 1.25rem 0;
  padding: .3rem 0 .3rem 1.1rem;
  border-left: 3px solid var(--vitral-pane-1);
  color: var(--vitral-muted);
}
.doc-prose hr { border: 0; border-top: 1px solid var(--vitral-came-soft); margin: 2rem 0; }

@media (max-width: 52rem) {
  .doc-cards { grid-template-columns: 1fr; }
  .doc-index li { grid-template-columns: 2rem 1fr; }
  .doc-index .doc-meta { grid-column: 2; }
}

/* The name, as its own page: the word set large, the anatomy of the window,
   then the guide itself. */
.name-hero, .anatomy, .name-rule, .name-story { max-width: 1100px; margin: 0 auto; padding: 0 1.25rem; }
.name-hero { text-align: center; }

/* Declared after both hero sections' own padding shorthand so it wins the
   cascade on each: the mark sits at the same offset whichever page it is on. */
.hero, .name-hero { padding-top: 2.25rem; }
/* Centred wherever they land, not just under .name-hero's own text-align: the
   word and its gloss are meant to look the same on any page that uses them,
   including the homepage where the surrounding section is left-aligned. */
.name-word {
  margin: 0;
  text-align: center;
  font-size: clamp(3rem, 9vw, 5.5rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1;
  background: linear-gradient(115deg, var(--vitral-ink) 18%, rgb(25, 112, 176) 52%, rgb(120, 86, 200) 78%, rgb(186, 106, 72));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.name-gloss { margin: .6rem 0 0; text-align: center; font-size: 1.15rem; color: var(--vitral-muted); }
.name-lede { margin: 1.25rem auto 0; font-size: 1.1rem; }

/* Room to breathe before whatever heads the section: on the name page that is
   the lede's own top margin, but the homepage's headline has none of its own. */
.name-gloss + h1 { margin-top: 2rem; }

.anatomy, .name-rule, .name-story { padding-top: 3.5rem; }
.anatomy h2 { font-size: 1.65rem; margin: 0 0 .5rem; letter-spacing: -0.02em; }
.anatomy-parts { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1rem; margin-top: 1.5rem; }
.anatomy-part { padding: 1.2rem 1.15rem; }
.anatomy-term { margin: 0; font-size: 1.35rem; font-weight: 700; letter-spacing: -0.02em; }
.anatomy-means { margin: .1rem 0 .6rem; font-size: .72rem; font-weight: 650; letter-spacing: .09em;
                 text-transform: uppercase; color: var(--vitral-muted); }
.anatomy-part p:last-child { margin: 0; color: var(--vitral-muted); font-size: .9rem; line-height: 1.55; }

.name-rule blockquote {
  margin: 0 0 1rem;
  padding: 0 0 0 1.25rem;
  border-left: 4px solid;
  border-image: linear-gradient(var(--vitral-pane-1), var(--vitral-pane-3), var(--vitral-pane-4)) 1;
  font-size: clamp(1.3rem, 3vw, 1.75rem);
  line-height: 1.35;
  letter-spacing: -0.015em;
  max-width: 38ch;
}
/* The story reads at the same measure as a document page: the prose's 74ch,
   the pane's padding and border, and this section's own side padding. */
.name-story { max-width: calc(74ch + 4.5rem + 2px + 2.5rem); }

@media (max-width: 64rem) { .anatomy-parts { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 40rem) { .anatomy-parts { grid-template-columns: 1fr; } }

/* Who made it, people and agent alike, said plainly rather than hidden in a
   commit log nobody opens. */
.footer-people {
  max-width: 1100px;
  margin: 2.5rem auto 0;
  padding: 0 1.25rem;
  display: grid;
  grid-template-columns: minmax(18rem, 30rem) 1fr;
  gap: 1.25rem 2.5rem;
  align-items: start;
}
.footer-people h2 { grid-column: 1 / -1; }
.footer-people h2 {
  margin: 0 0 .8rem;
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--vitral-muted);
}
.footer-people ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .6rem 1.4rem;
}
.footer-people li {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  font-size: .92rem;
  font-weight: 550;
}
.person-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  font-size: .68rem;
  font-weight: 650;
  letter-spacing: .02em;
  color: var(--vitral-ink);
  background: linear-gradient(rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.6)), var(--vitral-pane-1);
  border: 1px solid var(--vitral-came-soft);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
}
.footer-people li:nth-child(2) .person-mark {
  background: linear-gradient(rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.6)), var(--vitral-pane-2);
}
.person-photo { padding: 0; object-fit: cover; background: none; }
.footer-people a { display: inline-flex; align-items: center; gap: .55rem; text-decoration: none; color: inherit; }
.footer-people a:hover { text-decoration: underline; }

.person-ai {
  background: linear-gradient(rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.55)), var(--vitral-pane-5);
  color: rgb(96, 68, 190);
}
.footer-note {
  margin: 0;
  max-width: 62ch;
  color: var(--vitral-muted);
  font-size: .85rem;
  line-height: 1.6;
}

.footer-fine {
  max-width: 1100px;
  margin: 2.75rem auto 0;
  padding: 1.5rem 1.25rem 0;
  border-top: 1px solid var(--vitral-came-soft);
  color: var(--vitral-muted);
  font-size: .85rem;
  line-height: 1.6;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.5rem;
  align-items: center;
  justify-content: space-between;
}
.footer-fine p { margin: 0; max-width: 62ch; }

/* The makers, at the bottom right where a reader finishes. The logo is the
   company's own file, so it keeps its own colours rather than being tinted
   into the glass. */
.footer-makers {
  display: grid;
  justify-items: end;
  gap: .45rem;
  text-align: right;
  font-size: .78rem;
  color: var(--vitral-muted);
}
.footer-makers a { display: inline-flex; }
.footer-makers img {
  display: block;
  height: 84px;
  width: auto;
  border-radius: 10px;
  transition: transform .3s cubic-bezier(.2, .7, .3, 1);
}
.footer-makers a:hover img { transform: translateY(-2px); }
.footer-copyright a { display: inline; color: inherit; text-decoration: none; }
.footer-copyright a:hover { text-decoration: underline; }

a { color: rgb(25, 112, 176); }

@media (max-width: 52rem) {
  .cards, .qa-grid, .demo-grid, .demo-grid-3, .demo-grid-4 { grid-template-columns: 1fr; }
  .demo-wide, .demo-grid-4 .demo-wide { grid-column: span 1; }
}

/* The footer's desktop grid needs 46.5rem (its four columns' floors plus
   gaps) to avoid overflowing, and inside the shell that floor is crossed by
   the column's own width, not the viewport's, whenever the sidebar is
   showing (.shell-main is the query container, above). Two flexible
   columns, brand spanning both, rather than reusing the phone layout's
   centred single column below, which is a much bigger jump than this width
   warrants and does not follow from a container this much narrower. */
@container (max-width: 46.5rem) {
  .site-footer-inner { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer-brand { grid-column: 1 / -1; max-width: none; }
  .footer-people { grid-template-columns: 1fr; }
}

/* The footer's four columns have a floor (minmax(18rem, ...) alone is wider
   than a phone), so below the nav's own breakpoint it stacks instead. */
@media (max-width: 40rem) {
  .site-footer-inner { grid-template-columns: 1fr; }
  .footer-people { grid-template-columns: 1fr; }

  /* Centred the same way the phone nav's own links are, now that each group
     is a single narrow column rather than the desktop's left-anchored row.
     The two paragraphs of running prose (the tagline and the agent
     authorship note) are left out of it and stay left aligned: a heading or
     a one-line link centres cleanly, but several lines of prose centred goes
     ragged on both edges instead of one, which reads worse the longer it
     runs. */
  .footer-brand { flex-direction: column; align-items: center; text-align: center; }
  .footer-tag { text-align: left; }

  .footer-links h2,
  .footer-links ul { text-align: center; }

  .footer-people h2 { text-align: center; }
  .footer-people ul { flex-direction: column; align-items: center; }

  /* footer-fine already wraps onto two lines at this width; space-between
     then leaves a single-item line sitting at its flex-start (left) instead
     of centred. The colophon paragraph is prose and stays left aligned by
     the same rule as .footer-tag above, so only the makers block's own
     alignment (set to "end" for the desktop right column) needs to flip. */
  .footer-fine { justify-content: center; }
  .footer-makers { justify-items: center; text-align: center; }
}

/* Fenced snippets: a clear strip rather than a pane, so the glass behind
   shows through. The tokens are marked by hand in the view: a few fixed
   snippets do not justify a highlighter, and hand marking cannot be wrong
   about a language it was written in. */
.code pre, .theming-section pre {
  margin: 1.25rem 0;
  padding: 1rem 1.25rem;
  overflow-x: auto;
  line-height: 1.6;
  border-radius: .5rem;
  background: rgba(22, 32, 43, 0.06);
}
.code pre code, .theming-section pre code { background: none; border: 0; padding: 0; font-size: .875rem; }

.t-k { color: #7a4fd0; }
.t-c { color: #1a6fd0; }
.t-m { color: #0d7a70; }
.t-s { color: #a8631a; }
.t-l { color: #55626f; }
.t-str { color: #b0395c; }
.t-e { color: #8792a0; }

.install { display: inline-flex; align-items: stretch; gap: 0; margin: 0 0 .75rem; }
.install-line {
  border-radius: 8px 0 0 8px; border-right: 0; padding: .5rem .85rem;
  font-size: .9rem; white-space: nowrap; display: inline-flex; align-items: center;
}
.install-copy {
  font: inherit; font-size: .85rem; font-weight: 550; cursor: pointer;
  padding: .5rem .9rem; min-width: 5.2rem;
  color: var(--vitral-ink);
  background: var(--vitral-glass-strong);
  border: 1px solid var(--vitral-came-soft);
  border-radius: 0 8px 8px 0;
}
.install-copy:hover { border-color: var(--vitral-came); }

/* The theming reference page. Its own layout only: everything it demonstrates
   is Janela's or vitral's, named on the page so a reader can find it. */
.theming-section { margin: 0 0 4rem; }
.theming-section h2 { margin: 0 0 0.5rem; font-size: 1.25rem; }
.theming-section > p { max-width: 62ch; }
.theming-note { margin: 0.5rem 0 2rem; font-size: 0.875rem; opacity: 0.7; }
.theming-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2rem; }
.theming-pair h3 { margin: 0 0 0.5rem; font-size: 1rem; }
@media (max-width: 40rem) { .theming-pair { grid-template-columns: minmax(0, 1fr); } }

/* Two properties changed and nothing else, so the panes inside visibly move
   without a single rule of their own being overridden. */
.theming-retheme { --janela-space: 0.45rem; --janela-accent: #7c3aed; }

/* The chart palette specimen. The neutral block restates Janela's own defaults
   so the two sets sit side by side on one page. */
.palette-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); gap: 0.75rem; margin: 1rem 0 1.5rem; }
.palette-swatch { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.8125rem; }
.palette-swatch code { font-size: 0.75rem; }
.palette-chip { display: block; height: 2.75rem; border-radius: 6px; background: var(--specimen); border: 1px solid var(--vitral-came-soft); }
.palette-value { font-variant-numeric: tabular-nums; opacity: 0.7; }
.theming-palette-neutral {
  --janela-series-2: #eb6834; --janela-series-3: #1baf7a; --janela-series-4: #eda100; --janela-series-5: #e87ba4;
  --janela-series-6: #008300; --janela-series-7: #4a3aa7; --janela-series-8: #e34948; --janela-series-other: #8c8c8c;
}

/* The two halves of the own-headings demonstration. The label says which is
   which, and the host's own heading is deliberately unlike a caption so the
   difference is visible rather than asserted. */
.theming-label { margin: 0 0 0.75rem; font-size: 0.8125rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; opacity: 0.55; }
.theming-own-heading { margin: 0 0 0.5rem; font-size: 1.05rem; color: #7c3aed; }

/* The demo's own content partial (ADR 039): an icon beside the analyst's
   heading, the kind of markup a host writes once and an analyst places. */
.demo-overview-heading { display: grid; grid-template-columns: auto 1fr; gap: .25rem .75rem; align-items: center; }
.demo-overview-heading svg { color: var(--vitral-ink); }
.demo-overview-heading h2 { margin: 0; font-size: 1.25rem; letter-spacing: -0.01em; }
.demo-overview-heading p { grid-column: 2; margin: 0; color: var(--vitral-muted); }

/* The language picker sits last in the menu and is named in its own language. */
.nav-language { font-weight: 600; }

/* Shown on a page that is still English inside the Portuguese menu (ADR 061). */
.locale-notice {
  margin: 0 auto; max-width: 1100px; padding: .6rem 1.25rem;
  font-size: .9rem; color: var(--vitral-muted); text-align: center;
}
.locale-notice a { font-weight: 600; }
