/* boreale-site (README.md), v4.2: the page chrome every Boréale site shares,
   loaded after boreale.css and before the site's own site.css, which keeps
   its content (hero, mock visuals, documentation) and nothing of this.
   PlayGuard's look is the reference: the header (72px, one row from 1081px,
   two below), the sky behind it, 1180px of content between 16px gutters, the
   88px rhythm of sections, buttons, the card with its pointer glow, the pill
   over a title, the footer under its horizon. Site.header(), Site.sky() and
   Site.footer() write the markup; chrome.js moves the sky, the glow and the
   reveal. A page that is not dark does not load it (boreale.css alone). */

:root {
  /* Beside Boréale's colours (boreale.css): a second night, a lighter dusk
     and the links' blue, for their contrast on the night. */
  --night-2: #12213f;
  --dusk: #8593ae;
  --link: #6fd0ff;
  /* What a page's parts are made of; a site may name more of its own. */
  --bg: var(--abyss);
  --surface: var(--night);
  --surface-2: var(--night-2);
  --text: var(--snow);
  --muted: var(--mist);
  --line: var(--night-line);
  --accent: var(--aurora);
  --accent-soft: rgb(0 255 204 / 0.08);
  --amber: #ffb86b;
  --shadow: 0 20px 50px -24px rgb(0 0 0 / 0.7);
  --body: "Figtree", system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* The page's sides: 16px, more beside an iPhone's notch in landscape
     (viewport-fit=cover). The content is --content wide between them; the
     header, hero and footer start at --edge-l and end at --edge-r. */
  --content: 1180px;
  --gutter-l: max(16px, env(safe-area-inset-left));
  --gutter-r: max(16px, env(safe-area-inset-right));
  --edge-l: max(var(--gutter-l), calc((100% - var(--content)) / 2));
  --edge-r: max(var(--gutter-r), calc((100% - var(--content)) / 2));
}

* { box-sizing: border-box; }
/* iOS enlarges the text when the phone turns to landscape, unless told not to. */
html { background: var(--abyss); scroll-behavior: smooth; scroll-padding-top: 24px; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { margin: 0; background: var(--bg); color: var(--text); font: 16.5px/1.6 var(--body); -webkit-font-smoothing: antialiased; }
a { color: var(--link); text-underline-offset: 3px; }
img, video { max-width: 100%; }
/* The family's headings: Sora 600, 1.2, -0.02em. Every h1-h3 of the page, the
   chrome's own and a site's unstyled ones; a heading that wants another weight
   or tracking sets it. An h4 has the same look inside the chrome's own parts
   (a section, a card, a band), at zero specificity; elsewhere (a document's
   prose) it stays the browser's. */
h1, h2, h3 { font-family: var(--display); font-weight: 600; line-height: 1.2; letter-spacing: -0.02em; text-wrap: balance; }
:where(.section, .section-head, .card, .band) h4 { font-family: var(--display); font-weight: 600; line-height: 1.2; letter-spacing: -0.02em; text-wrap: balance; }
:focus-visible { outline: 2px solid var(--aurora); outline-offset: 3px; }
/* For a screen reader only. */
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.skip { position: absolute; left: -999px; top: 8px; background: var(--surface); color: var(--text); padding: 8px 12px; border-radius: 8px; z-index: 10; }
.skip:focus { left: 8px; }

/* Line breaks as each script wants them: Japanese between phrases, Korean
   between words, Chinese without a punctuation mark opening a line. */
:lang(ja) :is(h1, h2, h3, .eyebrow, .button, .pill-eyebrow, .nav a, .band p, figcaption) { word-break: auto-phrase; }
:lang(ko) body { word-break: keep-all; }
:lang(zh-Hans) body, :lang(zh-Hant) body { line-break: strict; }
:is(:lang(zh-Hans), :lang(zh-Hant)) :is(h1, h2, h3) { word-break: keep-all; overflow-wrap: anywhere; }

/* ---- The sky: the canvas (chrome.js) behind a home page's header and hero;
   without script, or with less motion asked, the same aurora as a gradient.
   Any other page has a quieter one (no .sky-home, no canvas). */
.sky { position: relative; isolation: isolate; overflow: hidden; }
.sky::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background:
    radial-gradient(70% 140% at 15% -60%, rgb(0 255 204 / 0.16), transparent 70%),
    radial-gradient(60% 140% at 85% -60%, rgb(138 92 255 / 0.18), transparent 70%),
    var(--abyss);
}
.sky:not(.sky-home) { border-bottom: 1px solid var(--line); }
.sky-home::before {
  background:
    radial-gradient(120% 60% at 30% -10%, rgb(0 255 204 / 0.2), transparent 60%),
    radial-gradient(90% 50% at 75% -5%, rgb(138 92 255 / 0.22), transparent 60%),
    radial-gradient(80% 40% at 55% 10%, rgb(51 187 255 / 0.14), transparent 70%),
    var(--abyss);
}
.sky canvas { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; display: block; }
.sky-home::after { content: ""; position: absolute; inset: auto 0 0 0; height: 40%; z-index: -1; background: linear-gradient(to top, var(--abyss), transparent); }
/* The night goes on under a home's hero: veils of aurora down the page and
   faint stars. */
.sky-home:not(.no-veils) ~ main { position: relative; isolation: isolate; }
.sky-home:not(.no-veils) ~ main::before, .sky-home:not(.no-veils) ~ main::after { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.sky-home:not(.no-veils) ~ main::before {
  background:
    radial-gradient(45% 22% at -5% 22%, rgb(0 255 204 / 0.07), transparent 70%),
    radial-gradient(45% 22% at 105% 45%, rgb(138 92 255 / 0.09), transparent 70%),
    radial-gradient(50% 20% at -5% 72%, rgb(51 187 255 / 0.07), transparent 70%),
    radial-gradient(45% 18% at 105% 92%, rgb(0 255 204 / 0.06), transparent 70%);
}
.sky-home:not(.no-veils) ~ main::after {
  opacity: 0.55;
  background-image:
    radial-gradient(1px 1px at 24px 36px, #e8eef7, transparent), radial-gradient(1px 1px at 132px 92px, #e8eef7, transparent),
    radial-gradient(1.4px 1.4px at 210px 18px, #e8eef7, transparent), radial-gradient(1px 1px at 300px 160px, #e8eef7, transparent),
    radial-gradient(1px 1px at 70px 210px, #a9b6cc, transparent), radial-gradient(1.2px 1.2px at 380px 260px, #a9b6cc, transparent);
  background-size: 420px 300px;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 75%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 12%, #000 75%, transparent);
}

/* ---- The header (Site.header()): the name and its menu of Boréale's sites,
   the page's links, the call to action in the aurora's gradient (the pill),
   GitHub, then the languages at the right. 72px. */
.top { display: flex; align-items: center; gap: 20px; padding: 14px var(--edge-r) 14px var(--edge-l); }
.brand { display: flex; align-items: center; gap: 10px; min-height: 44px; text-decoration: none; color: var(--text); font: 700 20px var(--display); letter-spacing: -0.02em; }
.brand b { color: var(--text); font-weight: 700; }
.nav { display: flex; gap: 4px; flex: 1; }
.nav a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 12px; border-radius: 10px; color: var(--muted); text-decoration: none; font-weight: 500; font-size: 15px; white-space: nowrap; }
.nav a[aria-current] { color: var(--text); }
.nav .nav-cta { color: var(--abyss); background: var(--aurora-grad); font-weight: 600; }
.nav .nav-cta[aria-current] { color: var(--abyss); }
.settings { gap: 8px; }
/* The header on two rows until its links, menus and name fit on one: up to
   1080px, for the longer languages (a phone in landscape, a small tablet).
   The links on a row of their own, the pill first, a row to scroll whose edge
   fades while there is more (chrome.js); GitHub is in the footer. */
@media (max-width: 1080px) {
  .top { flex-wrap: wrap; gap: 10px 16px; }
  .nav { order: 3; flex-basis: 100%; overflow-x: auto; gap: 4px; scrollbar-width: none; margin: -6px 0 -4px; }
  .nav.more { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent); }
  .nav a { padding: 0 10px; }
  .nav a:first-child:not(.nav-cta) { padding-left: 0; }
  .nav .nav-cta { order: -1; padding: 0 14px; margin-right: var(--cta-gap, 0); }
  .nav .nav-gh { display: none; }
  .settings { margin-left: auto; gap: 6px; }
  .lang-name { display: none; }
  .lang-code { display: inline; }
}
@media (max-width: 860px) {
  .brand { font-size: 18px; gap: 8px; }
  .brand img { width: 28px; height: 28px; }
}

/* ---- Text and buttons. */
/* A section's subject over its title, in the aurora's colour. The line height
   is --eyebrow-leading, `normal` as PlayGuard's (the `font` shorthand would
   reset it to that anyway); a site whose text sets 1.6 puts it on :root. */
.eyebrow { margin: 0 0 10px; font: 400 13px/var(--eyebrow-leading, normal) var(--mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--aurora); overflow-wrap: anywhere; }
/* The pill over a title: the latest release, a status. A link or a span. */
.pill-eyebrow { margin: 0 0 18px; }
.pill-eyebrow > :where(a, span):not(.pill-more) {
  display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 4px 12px;
  border: 1px solid rgb(0 255 204 / 0.35); border-radius: 999px; background: rgb(0 255 204 / 0.08);
  color: var(--aurora); font: 500 13px/var(--eyebrow-leading, normal) var(--mono); text-decoration: none;
}
.pill-eyebrow.caps > :not(.pill-more) { text-transform: uppercase; letter-spacing: 0.04em; }
/* ... and beside it a link to more (what changed): plain, with an arrow. */
.pill-eyebrow:has(.pill-more) { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; }
.pill-eyebrow .pill-more { display: inline-flex; align-items: center; min-height: 32px; color: var(--snow); font-size: 15px; text-decoration: underline; text-decoration-color: rgb(232 238 247 / 0.4); }
.pill-eyebrow .pill-more::after { content: "\00a0→"; color: var(--aurora); }
.actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 48px; padding: 0 20px;
  border-radius: 12px; border: 1px solid var(--line); background: rgb(11 20 36 / 0.4);
  color: var(--text); text-decoration: none; font-weight: 600; font-size: var(--button-size, inherit);
}
.button.primary { background: var(--snow); border-color: var(--snow); color: var(--abyss); }
/* Hover only where there is a pointer: a finger's tap would leave it on. */
@media (hover: hover) {
  a:hover { color: var(--aurora); }
  .brand:hover { color: var(--text); }
  .nav a:hover { color: var(--text); background: rgb(232 238 247 / 0.06); }
  .nav .nav-cta:hover { color: var(--abyss); background: var(--aurora); }
  .button:hover { border-color: var(--mist); }
  .button.primary:hover { background: var(--aurora); border-color: var(--aurora); color: var(--abyss); }
  .pill-eyebrow > a:not(.pill-more):hover { border-color: var(--aurora); color: var(--aurora); }
}

/* ---- Sections: 1180px of content between the gutters, an 88px rhythm
   (less on a phone), the eyebrow, the title and a lead paragraph. */
.wrap { max-width: calc(var(--content) + 32px); margin: 0 auto; padding-left: var(--gutter-l); padding-right: var(--gutter-r); }
.section { max-width: calc(var(--content) + 32px); margin: 0 auto; padding: clamp(48px, 7vw, 88px) var(--gutter-r) 0 var(--gutter-l); }
.section > h2, .section-head h2 { font-size: clamp(1.75rem, 4vw, 2.5rem); letter-spacing: -0.025em; margin: 0 0 28px; }
.section-head { display: grid; gap: 10px; margin-bottom: 32px; }
.section-head .eyebrow, .section-head h2 { margin: 0; }
/* The lead keeps a measure; the title takes the width it needs. */
.section-head p:not(.eyebrow) { margin: 0; max-width: 64ch; color: var(--muted); }
/* A hero (the site's own) starts at the header's edge, 1180px of content. */
:where(.hero) { padding-left: var(--edge-l); padding-right: var(--edge-r); }
/* Paragraphs and headings without the browser's margins, where a site asks
   (class on <body> or any container). Zero specificity: a rule of its own wins. */
:where(.reset-margins) :where(p, h1, h2, h3, h4) { margin: 0; }
/* A <main class="wrap"> already has the gutters, and a band in a section too:
   what is inside takes none of its own. */
.wrap > .section { padding-left: 0; padding-right: 0; }
.wrap > .section:not(.narrow) { max-width: none; }
.wrap > .band, .section > .band { margin-left: 0; margin-right: 0; max-width: none; }
/* ... and when it opens its container, the container's padding is the space above it. */
.wrap > .band:first-child, .section > .band:first-child { margin-top: 0; }
.section.narrow { max-width: 720px; padding-bottom: 80px; }
.lede { color: var(--muted); font-size: clamp(1.0625rem, 1.6vw, 1.15rem); max-width: 56ch; }
/* The closing call to action of a page. */
.band {
  margin: clamp(48px, 7vw, 88px) var(--gutter-r) 0 var(--gutter-l); max-width: var(--content);
  display: flex; align-items: center; justify-content: space-between; gap: 20px 32px;
  border: 1px solid var(--line); border-radius: var(--radius); padding: clamp(22px, 4vw, 40px);
  background: radial-gradient(80% 140% at 0% 0%, rgb(0 255 204 / 0.14), transparent 60%),
              radial-gradient(70% 140% at 100% 100%, rgb(138 92 255 / 0.18), transparent 60%), var(--night);
}
.band > div:first-child { max-width: 62ch; }
/* Buttons beside the text, one under the other; the width of the band on a phone. */
.band-actions { display: flex; flex-direction: column; gap: 10px; flex: none; }
.band h2 { margin: 0 0 10px; font-size: clamp(1.5rem, 3.4vw, 2.1rem); letter-spacing: -0.025em; }
.band p { margin: 0; color: var(--muted); }
/* An eyebrow in a band: `.band p` wins over `.eyebrow`, and PlayGuard's is the
   text's grey; a site that wants the aurora's puts --band-eyebrow on :root. */
.band .eyebrow { color: var(--band-eyebrow, var(--muted)); }
@media (min-width: 1212px) { .band { margin-left: auto; margin-right: auto; } }
@media (max-width: 600px) {
  .band { flex-direction: column; align-items: flex-start; margin: 48px var(--gutter-r) 0 var(--gutter-l); padding: 24px 20px; }
  .band .button { align-self: stretch; text-align: center; }
  .band-actions { align-self: stretch; }
}

/* ---- The card: under the pointer its edge lights up in the aurora where
   the pointer is (chrome.js sets --mx and --my). */
.cards { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--cards-min, 250px)), 1fr)); gap: 16px; }
.card { position: relative; display: grid; gap: 10px; align-content: start; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 22px; transition: transform 0.3s, border-color 0.3s; }
.card h3 { margin: 0; font-size: 18px; letter-spacing: -0.01em; }
.card p { margin: 0; color: var(--muted); font-size: 15.5px; }
.card .icon { display: block; box-sizing: border-box; width: 44px; height: 44px; padding: 10px; border-radius: 12px; color: var(--aurora);
              background: linear-gradient(135deg, rgb(0 255 204 / 0.16), rgb(138 92 255 / 0.14)); box-shadow: inset 0 0 0 1px rgb(0 255 204 / 0.22); }
.card::before {
  content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 1px; pointer-events: none; opacity: 0; transition: opacity 0.3s;
  background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 0%), rgb(0 255 204 / 0.85), rgb(138 92 255 / 0.4) 45%, transparent 75%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
@media (hover: hover) {
  .card:hover { transform: translateY(-3px); }
  .card:hover::before { opacity: 1; }
}
/* An icon: its strokes, as the sites' drawings carry them. */
.card svg.icon { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
@media (max-width: 860px) {
  .cards { gap: 12px; }
  .card { padding: 16px; }
  /* Its icon beside the title, its text under the title; a card without an icon
     stays a stack, and so does a `.stack` one (a card that ends in a <pre> or a
     table, whose width a column would take). `.below`: the text under both,
     the whole width of the card. */
  .card:where(:not(.stack)):has(> .icon) { grid-template-columns: auto minmax(0, 1fr); gap: 4px 14px; }
  .card:where(:not(.stack)):has(> .icon) > .icon { grid-row: span 2; }
  .card.below:has(> .icon) { grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 8px 14px; }
  .card.below:has(> .icon) > .icon { grid-row: auto; }
  .card.below:has(> .icon) > :not(.icon, h3, h4) { grid-column: 1 / -1; }
}
@media (max-width: 600px) {
  .cards { grid-template-columns: minmax(0, 1fr); }
}

/* ---- The footer (Site.footer()): the project, its columns, Boréale's sites
   (sites.json) and the support, under a horizon of aurora. */
/* 88px above it, --footer-gap: a site whose last section carries its own space
   under it puts 0 on :root rather than have the two stack. */
.footer { position: relative; margin-top: var(--footer-gap, 88px); background: linear-gradient(180deg, rgb(14 26 51 / 0.5), transparent); }
.footer-inner { max-width: calc(var(--content) + 32px); margin: 0 auto; padding: 40px var(--gutter-r) calc(32px + env(safe-area-inset-bottom)) var(--gutter-l); color: var(--dusk); font-size: 15px; }
.footer a { color: var(--muted); }
.footer strong { color: var(--text); font: 600 17px var(--display); }
.footer img { vertical-align: -4px; }
.footer-cols { display: grid; grid-template-columns: 1.4fr; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 28px; margin-bottom: 24px; }
.footer-cols p { margin: 0 0 8px; }
.footer h2 { font: 400 12px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; color: var(--mist); margin: 0 0 10px; }
.footer ul { list-style: none; padding: 0; margin: 0; }
.footer li { margin: 4px 0; }
.footer-fine { font-size: 13px; }
.footer-cols > * { min-width: 0; overflow-wrap: anywhere; }
.footer a { overflow-wrap: anywhere; }
.footer::before {
  content: ""; position: absolute; left: 50%; top: 0; width: min(var(--content), 100%); height: 140px; transform: translateX(-50%); pointer-events: none;
  background: radial-gradient(50% 100% at 50% 0%, rgb(0 255 204 / 0.14), rgb(51 187 255 / 0.06) 45%, transparent 75%);
}
.footer::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px; background: var(--aurora-grad); opacity: 0.6;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 30%, #000 70%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 30%, #000 70%, transparent);
}
@media (max-width: 860px) {
  .footer a { display: inline-block; padding: 10px 0; }
  .footer-inner p { margin: 6px 0; }
  .footer-cols { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-auto-flow: row; gap: 16px; }
  .footer-cols > :first-child { grid-column: 1 / -1; }
  .footer li { margin: 0; }
}
@media (max-width: 420px) {
  .footer-cols { grid-template-columns: minmax(0, 1fr); }
}

/* ---- Motion: the sections rise into view once (chrome.js; not with less
   motion asked), and from one page to the next a short cross-fade, the
   header staying where it is (where the browser can). */
@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(26px); transition: opacity 0.8s ease, transform 0.8s cubic-bezier(0.2, 0.7, 0.2, 1); }
  .reveal.in { opacity: 1; transform: none; }
  .reveal .card { opacity: 0; transform: translateY(14px); transition: opacity 0.6s ease calc(var(--i, 0) * 70ms), transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) calc(var(--i, 0) * 70ms), border-color 0.3s; }
  .reveal.in .card { opacity: 1; transform: none; }
  @view-transition { navigation: auto; }
  .top { view-transition-name: top; }
  ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.25s; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .card, .card::before { transition: none; }
}

/* Printed: the text alone. */
@media print {
  .top, .sky canvas, .footer, .skip { display: none !important; }
  body { background: #fff; color: #000; font-size: 12pt; }
  .reveal, .reveal .card { opacity: 1 !important; transform: none !important; }
}
