/* Vale site. One stylesheet for index, 404, privacy and terms.
   Tokens first, then the sky behind every page, the base, the header pills,
   the footer and the go-to-top link, the notch, the landing page (hero and
   its cat, marquee, story, playground, install, Google Calendar, privacy),
   the walking cat, the legal pages. Dark is the default whatever the system
   scheme says; html[data-theme="light"] (the theme button, stored as
   vale-theme) switches to the light set. Contrast ratios are listed in
   docs/memory/site-landing.md. */

/* Geist and Geist Mono (SIL OFL 1.1, fonts/OFL.txt). Geist is the variable
   file (smaller than three statics); Geist Mono is only used at 400. */
@font-face { font-family: "Geist"; font-weight: 100 900; font-style: normal; font-display: swap; src: url("fonts/Geist-Variable.woff2") format("woff2"); }
@font-face { font-family: "Geist Mono"; font-weight: 400; font-style: normal; font-display: swap; src: url("fonts/GeistMono-Regular.woff2") format("woff2"); }

/* Dark, the default. */
:root {
  --bg: #17120F;
  --bg-2: #1E1815;
  --text: #F4EDE4;
  --text-2: #A89A8B;
  --line: #3A302A;
  --control: #8A7D70;
  --ink: #E2683C;
  --focus: #E2683C;
  /* The terracotta and the secondary text for copy that can sit on a sky glow
     (the story's counter, page name and line on a phone). */
  --ink-hi: #F0896A;
  --text-2-hi: #B9AC9D;
  --code-bg: #221B17;
  --btn-bg: #E2683C;
  --btn-bg-hover: #EC7C55;
  --btn-text: #17120F;
  /* A tint behind text that would otherwise sit on a sky glow, and the card face. */
  --panel: rgba(18, 14, 13, .74);
  --card: rgba(30, 24, 21, .88);
  --sky-fallback: #110D10;
  --bubble-bg: #F4EDE4;
  --bubble-text: #17120F;

  /* The notch is the same in both themes; in the dark theme its surface is
     the page colour, so a 1 px edge (3.41 on the page) keeps its outline. */
  --notch-bg: #17120F;
  --notch-text: #F4EDE4;
  --notch-2: #A89A8B;
  --notch-accent: #E2683C;
  --notch-line: #3A302A;
  --notch-edge: #75675B;

  /* Screens (the story mock, the playground pictures) are dark in both themes. */
  --scr-bg: #0E0B09;
  --scr-edge: #3A302A;
  --scr-text: #F4EDE4;
  --scr-2: #A89A8B;

  /* The cat's coat. site.js changes these on <html> when a coat chip is chosen;
     the hero cat, the notch cats, the picture cats and the walking cat read them. */
  --coat: #E2683C;
  --earl: #E2683C;
  --earr: #E2683C;
  --eye: #17120F;
  --rim: transparent;
  --pa: 0;
  /* The go-to-top tail: its tip colour (set with the coat) and its outline. */
  --tip: #F4EDE4;
  --tail-edge: #A89A8B;
  --tail-halo: #17120F;

  /* Page progress 0 to 1, set by site.js: the sky mixes dusk, night and dawn. */
  --p: 0;

  --gutter: clamp(16px, 4vw, 40px);
  /* The header pills sit this far from the left and right edges. */
  --edge: 16px;
  --i-download: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v11M7 10.5l5 5 5-5M5 20h14'/%3E%3C/svg%3E");
  --i-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='9' width='11' height='11' rx='2.5'/%3E%3Cpath d='M5 15V6.5A2.5 2.5 0 0 1 7.5 4H15'/%3E%3C/svg%3E");
  --i-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  --font: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Geist Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
  color-scheme: dark;
}
:root[data-theme="light"] {
  --bg: #F6F6F4;
  --bg-2: #ECEBE7;
  --text: #17120F;
  --text-2: #5C524A;
  --line: #DCD8D3;
  --control: #7A6E65;
  --ink: #A8431C;
  --focus: #A8431C;
  --ink-hi: #A8431C;
  --text-2-hi: #5C524A;
  --code-bg: #EBEAE6;
  --panel: rgba(252, 249, 244, .82);
  --card: rgba(255, 253, 249, .86);
  --sky-fallback: #F8F1E7;
  --bubble-bg: #17120F;
  --bubble-text: #F4EDE4;
  --notch-edge: #17120F;
  --tail-edge: #17120F;
  --tail-halo: #F6F6F4;
  color-scheme: light;
}
@media (min-width: 40em) { :root { --edge: 24px; } }

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background-color: var(--sky-fallback); }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
/* The body has no background of its own: html carries the fallback colour and
   the sky layers below sit between the two. body is a stacking context, so
   its two pseudo layers stay behind the page and above html::before. */
body {
  position: relative;
  isolation: isolate;
  margin: 0;
  color: var(--text);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.6;
  overflow-wrap: break-word;
}

/* ---------- the sky ----------
   Three fixed full-viewport moods mixed by --p (0 at the top of the page, 1
   at the end): html::before is the night, always there; body::before is dusk
   (full at the top, gone by p = .45); body::after is dawn with the terracotta
   horizon glow (from p = .62). Without script --p stays 0, so the page shows
   dusk. Opacity only, so the mix is cheap. The star canvas (site.js, index
   only) sits above all three, behind the page. */
html::before, body::before, body::after { content: ""; position: fixed; inset: 0; pointer-events: none; }
html::before {
  z-index: -1;
  background: radial-gradient(80% 60% at 80% 0, #1F1A2E 0, transparent 60%), linear-gradient(#0E0B10, #130F12);
}
body::before {
  z-index: -3;
  background: radial-gradient(120% 70% at 50% 110%, #7A3424 0, #3A1A22 35%, transparent 70%), linear-gradient(#120D12, #1A1015);
  opacity: calc(1 - var(--p) * 2.2);
}
body::after {
  z-index: -2;
  background: radial-gradient(130% 80% at 50% 120%, #E2683C 0, #7A3424 30%, #2A1712 60%, transparent 85%), linear-gradient(#140F10, #1E1410);
  opacity: calc(max(0, var(--p) - .62) * 2.8);
}
/* Light: a warm pale day. A soft sun glow at the top, a peach glow at the end. */
:root[data-theme="light"]::before {
  background: linear-gradient(#F8F2E9, #F6F1E9);
}
html[data-theme="light"] body::before {
  background: radial-gradient(70% 55% at 50% 0, #FFE6C4 0, rgba(255, 230, 196, 0) 70%), linear-gradient(#FCEEDC, #F8F2E9);
}
html[data-theme="light"] body::after {
  background: radial-gradient(130% 80% at 50% 120%, #F7BE9A 0, #F9D6BC 35%, rgba(249, 214, 188, 0) 80%), linear-gradient(#F8EFE4, #F7E8D9);
}
#sky { position: fixed; inset: 0; z-index: -1; width: 100%; height: 100%; pointer-events: none; }

img, svg { max-width: 100%; }
img { height: auto; display: block; }
/* Anchored headings land below the fixed header (pills end at 60 px). */
[id] { scroll-margin-top: 5rem; }
h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.1; letter-spacing: -.02em; text-wrap: balance; }
p { margin: 0 0 1em; }
strong, b, th { font-weight: 600; }
a { color: var(--ink); text-underline-offset: .18em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }
/* Geist Mono is loaded at 400 only, so mono text never asks for another weight. */
code, kbd { font-family: var(--mono); font-size: .9em; font-weight: 400; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* Helpers for what only makes sense with or without script (the inline head
   script adds .js). They only hide, so the element keeps its own display. */
html:not(.js) .js-only { display: none !important; }
.js .no-js-only { display: none !important; }
.wrap { width: min(100% - 2 * var(--gutter), 72rem); margin-inline: auto; }
.narrow { width: min(100% - 2 * var(--gutter), 49rem); }

/* The go-to-top link scrolls here and focuses it, so the next Tab is the skip link. */
#top { position: absolute; top: 0; left: 0; width: 1px; height: 1px; overflow: hidden; }
#top:focus { outline: none; }
.skip { position: absolute; left: 8px; top: -100px; z-index: 300; padding: .6rem 1rem; background: var(--bg); color: var(--text); border: 2px solid var(--focus); border-radius: 8px; text-decoration: none; font-weight: 600; }
.skip:focus { top: 8px; }

/* ---------- header: two pills that flank the notch ----------
   With script the header is fixed and spans the width, but only the pills
   take pointer events, so the notch between them stays reachable. The pills
   are transparent at the top of the page; site.js adds .is-scrolled once the
   page has moved, and they get the tint and a hairline. The border is always
   there (transparent at first), so the pills never change size. Their widths
   are measured against the idle notch (at least 12 px clear at every width),
   and site.js measures them to decide whether a wider notch state fits. */
.site-header { position: relative; z-index: 90; }
.nav-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; padding: 8px var(--edge); }
.js .site-header { position: fixed; top: 0; left: 0; right: 0; pointer-events: none; }
.js .nav-inner { flex-wrap: nowrap; }
.js .pill { pointer-events: auto; }
.pill { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 2px; padding: 3px; border: 1px solid transparent; border-radius: 999px; background: transparent; }
.js .is-scrolled .pill { background: var(--bg-2); border-color: var(--line); }
@media (prefers-reduced-motion: no-preference) {
  .pill { transition: background-color .3s ease-out, border-color .3s ease-out; }
}
.brand { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 12px 0 8px; border-radius: 999px; font-size: 1.0625rem; font-weight: 600; letter-spacing: -.01em; color: var(--text); text-decoration: none; }
.brand img { width: 28px; height: 28px; }
.site-nav ul { display: flex; flex-wrap: wrap; gap: 0; margin: 0; padding: 0; list-style: none; }
.site-nav a, .nav-gh { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 12px; border-radius: 999px; font-size: .9375rem; color: var(--text-2); text-decoration: none; white-space: nowrap; }
.site-nav a:hover, .nav-gh:hover { color: var(--text); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .3em; }
.site-nav a[aria-current="page"] { color: var(--text); }
/* Only in the dropdown under the Menu button. */
.nav-more { display: none; }
.btn-dl { display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px; border-radius: 999px; background: var(--btn-bg); color: var(--btn-text); font-size: .9375rem; font-weight: 600; text-decoration: none; white-space: nowrap; }
.btn-dl:hover { background: var(--btn-bg-hover); }
.btn-dl:focus-visible { outline-color: var(--text); }
.menu-btn, .theme-btn { min-height: 44px; border: 0; border-radius: 999px; background: transparent; color: var(--text); font: inherit; font-size: .9375rem; font-weight: 500; cursor: pointer; }
.menu-btn { display: none; align-items: center; gap: 6px; padding: 0 10px 0 8px; }
.menu-ico { position: relative; display: block; box-sizing: border-box; width: 18px; height: 14px; border-top: 2px solid currentColor; border-bottom: 2px solid currentColor; }
.menu-ico::after { content: ""; position: absolute; left: 0; right: 0; top: 4px; border-top: 2px solid currentColor; }
.theme-btn { display: inline-flex; align-items: center; justify-content: center; width: 44px; padding: 0; }
.theme-btn[hidden] { display: none; }
.theme-btn svg { width: 20px; height: 20px; }
.menu-btn:hover, .theme-btn:hover { background: var(--line); }

/* Wide enough for both full pills beside the idle notch (measured, see
   site-landing.md); narrower, the left pill is a Menu button and the right
   pill only Download. Without script nothing is folded away. Media queries
   count a classic scrollbar (15 to 17 px on Windows) but the notch centres on
   the width without it, so every fold below keeps 12 px with one: the full
   pills need 49em, not 48em. */
@media (max-width: 48.99em) {
  .js .menu-btn { display: inline-flex; }
  .js .pill-l .brand, .js .pill-r .nav-gh, .js .pill-r .theme-btn { display: none; }
  .js .pill-r { padding: 0; border-color: transparent !important; background: transparent !important; }
  /* Icon-only Menu at every width below 49em: the left pill is a 52 px circle
     (44 + 2 x 3 padding + 2 x 1 border). The right pill is 52 tall too (its
     Download link is 50 + 2 x 1 border), so both pills share top 8 and height. */
  .js .menu-btn { width: 44px; justify-content: center; padding: 0; }
  .js .menu-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .js .btn-dl { min-height: 50px; }
  .js .site-nav { display: none; position: absolute; left: -1px; top: calc(100% + 8px); width: min(17rem, calc(100vw - 2 * var(--edge))); padding: 8px; background: var(--bg-2); border: 1px solid var(--line); border-radius: 22px; }
  .js .site-nav.is-open { display: block; }
  .js .site-nav ul { flex-direction: column; }
  .js .site-nav li { display: block; }
  .js .site-nav a { width: 100%; padding: 0 14px; font-size: 1.0625rem; color: var(--text); }
  .js .site-nav a img { width: 24px; height: 24px; }
  .js .nav-theme { padding: 4px 2px 0; }
  .js .nav-theme .theme-btn { border: 1px solid var(--control); }
}
/* On phones the Menu pill must end 12 px before the 120 px notch (at 376 px
   with a scrollbar it has 93 px); below 23.5em the header shares 320 px with
   a 96 px notch: the Menu button keeps only its icon (the word stays as its
   accessible name) and Download gets smaller again (76 px room at 320 with a
   scrollbar). */
@media (max-width: 32.5em) {
  .btn-dl { padding: 0 9px; font-size: .875rem; }
}
@media (max-width: 23.49em) {
  .btn-dl { padding: 0 6px; font-size: .75rem; }
}
/* Below 20em (fold cover screens, about 280 px) the word no longer fits
   beside the 96 px notch with 12 px clear (it needs 312 px with a
   scrollbar), so Download becomes a 44 px download icon: clear from 263 px
   up. The word stays in the link, moved out of view, as its accessible
   name. Without script the header is static and keeps the word. */
@media (max-width: 19.99em) {
  .js .btn-dl { position: relative; width: 50px; padding: 0; overflow: hidden; white-space: nowrap; text-indent: 50px; }
  .js .btn-dl::before {
    content: ""; position: absolute; top: 50%; left: 50%; width: 20px; height: 20px; margin: -10px 0 0 -10px;
    background: currentColor; forced-color-adjust: none;
    -webkit-mask: var(--i-download) center / contain no-repeat; mask: var(--i-download) center / contain no-repeat;
  }
}

/* ---------- footer ---------- */
/* The footer text sits on the tint, never straight on the dawn glow. The
   bottom padding keeps the last links above the go-to-top tail. */
.site-footer { margin-top: clamp(4rem, 10vw, 8rem); border-top: 1px solid var(--line); padding-block: 2.5rem 6rem; background: var(--panel); }
.footer-inner { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 2rem; width: min(100% - 2 * var(--gutter), 78rem); margin-inline: auto; }
.footer-brand { margin: 0 auto 0 0; font-size: .9375rem; }
.footer-brand img { display: inline-block; width: 20px; height: 20px; margin-right: 4px; vertical-align: -4px; }
.footer-links { display: flex; flex-wrap: wrap; gap: 0 .25rem; margin: 0; padding: 0; list-style: none; }
.footer-links a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 .6rem; font-size: .9375rem; color: var(--text-2); }
.footer-links a:hover { color: var(--text); }
.footer-note { flex-basis: 100%; margin: 0; font-size: .875rem; color: var(--text-2); }

/* ---------- go to top ----------
   A cartoon cat tail, drawn in inline SVG, that starts flush at the right edge
   of the window (as if the cat sat just off screen), curves up and left in an S
   and ends in a curled tip. No disc: two outline rings, --tail-halo under
   --tail-edge, keep it at 3:1 or more against the page in both themes for every
   coat; the body is --coat and the tip --tip, so a coat chip recolours it. The box is 56 x 100
   (the viewBox pads 4 units on the left so the swish stays inside it). Without
   script it is always there, a plain #top link, still. With script site.js shows
   it once the hero has scrolled away (.is-shown): it slides in from the right
   edge with a small overshoot; hidden it is off screen, not focusable and not a
   hit target. Idle it swishes (a few degrees around its base), hover and focus
   make it quicker, and a click yanks it up out of the view (.is-yank). All of
   that is transform only and sits under no-preference motion. */
.to-top { position: fixed; right: 0; bottom: 16px; z-index: 80; display: block; width: 56px; height: 100px; }
.to-top svg { display: block; width: 56px; height: 100px; }
.to-top .tail { transform-origin: 52px 92px; }
.to-top path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.tail-halo { stroke: var(--tail-halo); stroke-width: 15; }
.tail-edge { stroke: var(--tail-edge); stroke-width: 12; }
.tail-body { stroke: var(--coat); stroke-width: 9; }
.tail-tip { stroke: var(--tip); stroke-width: 9; }
.to-top:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
@media (min-width: 40em) { .to-top { bottom: 24px; } }
.js .to-top:not(.is-shown) { transform: translateX(100%); visibility: hidden; pointer-events: none; }
.js.reveal-off .to-top { transform: none; visibility: visible; pointer-events: auto; }
@media (prefers-reduced-motion: no-preference) {
  .js .to-top { transition: transform .35s ease-in, visibility 0s linear .35s; }
  .js .to-top.is-shown { transition: transform .35s cubic-bezier(.34, 1.56, .64, 1), visibility 0s linear 0s; }
  .js .to-top.is-reset { transition: none !important; }
  .js .to-top.is-shown .tail { animation: tail-swish 2.6s ease-in-out infinite alternate; }
  .js .to-top:not(.is-shown) .tail { animation: none; }
  .js .to-top.is-shown:focus-visible .tail { animation-duration: .6s; }
  .js .to-top.is-yank { animation: tail-yank .7s linear forwards; pointer-events: none; }
  .js .to-top.is-yank .tail { animation: none; }
}
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .js .to-top.is-shown:hover .tail { animation-duration: .6s; }
}
@keyframes tail-swish { from { transform: rotate(-2.5deg); } to { transform: rotate(2.5deg); } }
@keyframes tail-yank {
  0% { transform: translateY(0); opacity: 1; animation-timing-function: ease-out; }
  18% { transform: translateY(8px); opacity: 1; animation-timing-function: cubic-bezier(.5, 0, .9, .45); }
  85% { opacity: 1; }
  100% { transform: translateY(-110vh); opacity: 0; }
}

/* ---------- the notch ---------- */
.notch {
  --nw: min(190px, calc(100vw - 32px));
  --nh: 34px;
  --nr: 17px;
  position: fixed; top: 0; left: 50%; z-index: 100;
  width: var(--nw); height: var(--nh);
  transform: translateX(-50%);
  background: var(--notch-bg);
  color: var(--notch-text);
  border: 1px solid var(--notch-edge); border-top: 0;
  border-radius: 0 0 var(--nr) var(--nr);
  overflow: hidden;
  font-size: 13px; line-height: 1.3;
  transition: width .35s ease-out, height .35s ease-out, border-radius .35s ease-out, box-shadow .3s ease-out;
}
.notch[data-state="clipboard"] { --nw: min(340px, calc(100vw - 32px)); --nh: 56px; --nr: 24px; }
.notch[data-state="greet"] { --nw: min(230px, calc(100vw - 32px)); --nh: 38px; --nr: 19px; }
/* .is-tight (site.js): the state keeps the idle footprint, because at full
   size it would touch a header pill. */
.notch:is([data-state="clipboard"], [data-state="greet"]).is-tight { --nw: min(190px, calc(100vw - 32px)); --nh: 34px; --nr: 17px; }
.notch.is-tight .nf-clip { justify-content: center; gap: 10px; }
.notch.is-tight .nc-lg { width: 24px; height: 24px; }
.notch.is-tight .clip-preview { display: none; }
.notch.is-tight .nf-greet { justify-content: center; gap: 8px; }
.notch[data-state].is-open { --nw: min(460px, calc(100vw - 32px)); --nh: 300px; --nr: 26px; }
/* The dragged hero cat is over the notch. */
.notch.is-glow { box-shadow: 0 0 0 3px rgba(226, 104, 60, .55), 0 0 50px rgba(226, 104, 60, .6); }
@media (max-width: 32.5em) {
  .notch[data-state="idle"],
  .notch:is([data-state="clipboard"], [data-state="greet"]).is-tight { --nw: 120px; --nh: 45px; --nr: 22px; }
  .notch .nf-idle { padding: 0 14px; }
  .notch.is-tight .nf-greet { padding: 0 10px; gap: 6px; }
  .notch.is-tight .greet-text { font-size: 12px; }
  .notch.is-tight .nf-greet .nc-lg { width: 20px; height: 20px; }
}
/* Below 23.5em (376 px) the idle footprint is 96 px, so the Menu and
   Download pills keep 12 px from it at 320 px. */
@media (max-width: 23.49em) {
  .notch[data-state="idle"],
  .notch:is([data-state="clipboard"], [data-state="greet"]).is-tight { --nw: 96px; }
  /* 94 px inside the 1 px edges: cat 26 + gap 10 + clock 39 + 2 x 9. */
  .notch .nf-idle, .notch.is-tight .nf-clip, .notch.is-tight .nf-greet { padding: 0 9px; }
  .notch.is-tight .nf-clip { gap: 8px; }
  /* 42 px are left for the title (76 - cat 26 - gap 8); "Copied" is 47 px at
     14 px and 41 px at 12 px. */
  .notch.is-tight .clip-title { font-size: 12px; }
  .notch.is-tight .nf-greet .nc-lg { display: none; }
}
.notch-face { position: absolute; top: 0; left: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.notch.is-open .notch-face { height: 44px; }
/* Without script the notch would be a button that does nothing, so it is not shown. */
html:not(.js) #notch { display: none; }
.notch :focus-visible { outline: 2px solid #F4EDE4; outline-offset: -4px; }
.notch .tab:focus-visible { outline-offset: 1px; border-radius: 6px; }

.nf { position: absolute; inset: 0; display: flex; align-items: center; gap: 10px; padding: 0 20px; opacity: 0; pointer-events: none; transition: opacity .18s ease-out; }
.notch[data-state="idle"] .nf-idle,
.notch[data-state="clipboard"] .nf-clip,
.notch[data-state="greet"] .nf-greet { opacity: 1; transition-delay: .12s; }
.notch.is-open .nf { opacity: 0; transition-delay: 0s; }
.notch.is-open .nf-open { opacity: 1; transition-delay: .1s; }

.nf-idle { justify-content: space-between; }
.nf-idle .clock { font-family: var(--mono); font-weight: 400; font-size: 13px; font-variant-numeric: tabular-nums; }
.nc { flex: none; overflow: visible; }
.nf-clip { padding: 0 16px; gap: 12px; }
.clip-text { display: flex; flex-direction: column; min-width: 0; }
.clip-title { font-weight: 600; font-size: 14px; white-space: nowrap; }
.clip-preview { color: var(--notch-2); font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nf-greet { padding: 0 16px; gap: 10px; }
.greet-text { font-weight: 600; font-size: 14px; white-space: nowrap; }

.nf-open { justify-content: space-between; padding: 0 20px; }
.nf-title { font-size: 16px; font-weight: 600; }
.nf-demo { color: var(--notch-2); font-size: 12px; }

.notch-panel[hidden] { display: none; }
.notch-panel { position: absolute; top: 44px; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; opacity: 0; transition: opacity .25s ease-out .1s; }
.notch.is-open .notch-panel { opacity: 1; }
.pg-wrap { flex: 1; min-height: 0; padding: 4px 20px 0; overflow: hidden; }
.pg[hidden] { display: none; }
.pg-sub { margin: 0 0 6px; color: var(--notch-2); font-size: 13px; }
.pg-big { margin: 0; font-size: 22px; font-weight: 600; line-height: 1.2; }
.pg-list, .pg-meters, .pg-tiles { margin: 0; padding: 0; list-style: none; }
.pg-list li { overflow-wrap: anywhere; display: flex; gap: 12px; align-items: baseline; padding: 9px 0; border-bottom: 1px solid var(--notch-line); font-size: 14px; }
.pg-list li:last-child { border-bottom: 0; }
.pg-list .t { flex: none; min-width: 4.5rem; color: var(--notch-2); font-family: var(--mono); font-weight: 400; font-size: 12px; }
.pg-list code { font-size: 13px; }
.pg-row { display: flex; align-items: center; gap: 18px; padding-top: 8px; }
.pg-grow { flex: 1; min-width: 0; }
.pg-bar { display: block; height: 6px; border-radius: 3px; background: var(--notch-line); overflow: hidden; }
.pg-bar > span { display: block; height: 100%; border-radius: 3px; background: var(--notch-accent); }
.cover { position: relative; flex: none; width: 22px; height: 22px; border-radius: 5px; background: var(--notch-line); }
.cover::after { content: ""; position: absolute; left: 6px; top: 6px; width: 10px; height: 10px; border-radius: 50%; background: var(--notch-accent); }
.cover-lg { width: 72px; height: 72px; border-radius: 12px; }
.cover-lg::after { left: 22px; top: 22px; width: 28px; height: 28px; }
.pg-grow .pg-bar { margin-top: 14px; }
.pg-meters li { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap: 12px; align-items: center; padding: 10px 0; font-size: 14px; }
.pg-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; padding-top: 6px; }
.pg-tiles li { display: flex; flex-direction: column; gap: 4px; padding: 12px; border-radius: 12px; background: #221B17; font-size: 13px; color: var(--notch-2); }
.pg-tiles b { color: var(--notch-text); font-weight: 600; font-size: 14px; }
.pg-code { margin: 6px 0 0; padding: 12px 14px; border: 1px solid var(--notch-line); border-radius: 10px; font-family: var(--mono); font-weight: 400; font-size: 13px; line-height: 1.7; }
.pg-code .pr { color: var(--notch-accent); }
.caret { display: inline-block; width: 7px; height: 14px; vertical-align: -2px; background: var(--notch-accent); }
.pg-minis { display: grid; grid-template-columns: repeat(3, 48px); gap: 14px 22px; padding: 10px 0 14px; color: var(--notch-2); }
.pg-minis svg { display: block; }
.pg-minis .on { color: var(--notch-accent); }

/* 14 tabs of 30 px plus 24 px padding fit the 458 px inside the open notch's edges. */
.dock { display: flex; justify-content: center; align-items: flex-end; height: 64px; padding: 0 12px 6px; }
.tab { display: flex; align-items: flex-end; justify-content: center; flex: none; width: 30px; height: 32px; margin: 0; padding: 0 0 7px; border: 0; background: transparent; color: var(--notch-2); cursor: pointer; }
.tab[aria-selected="true"] { color: var(--notch-accent); }
.dock-ico { width: 18px; height: 18px; transform-origin: 50% 100%; pointer-events: none; }
@media (pointer: coarse), (max-width: 32.5em) {
  .dock { justify-content: flex-start; overflow-x: auto; overflow-y: hidden; overscroll-behavior: contain; scrollbar-width: thin; padding-inline: 8px; }
  .tab { width: 44px; height: 44px; padding-bottom: 11px; }
  .dock-ico { width: 22px; height: 22px; }
}

/* ---------- landing page: type and buttons ---------- */
h1 { font-size: clamp(2.5rem, 1rem + 6.4vw, 5.75rem); line-height: .98; letter-spacing: -.045em; }
h2 { font-size: clamp(2rem, 1.25rem + 3vw, 3.5rem); line-height: 1.02; letter-spacing: -.035em; }
h3 { font-size: clamp(1.25rem, 1.1rem + .6vw, 1.5rem); letter-spacing: -.015em; }
.lead { font-size: clamp(1.125rem, 1rem + .5vw, 1.3125rem); line-height: 1.5; max-width: 36rem; color: var(--text-2); }

.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding: 0 24px; border: 1px solid transparent; border-radius: 999px; font: inherit; font-weight: 600; text-decoration: none; cursor: pointer; }
.btn-primary { background: var(--btn-bg); color: var(--btn-text); }
.btn-primary:hover { background: var(--btn-bg-hover); text-decoration: none; }
/* The Copy control of a command box (see .cmd below): an icon and a label,
   inside the box. Joined to the right edge on tablet and desktop, an
   icon-only square on phones. The icon is a mask on currentColor. */
.btn-copy { gap: 8px; min-height: 44px; font-size: .9375rem; font-weight: 500; color: var(--text); background: transparent; }
.copy-ico { display: block; flex: none; width: 20px; height: 20px; background: currentColor; forced-color-adjust: none; -webkit-mask: var(--i-copy) center / contain no-repeat; mask: var(--i-copy) center / contain no-repeat; }
.btn-copy.is-copied .copy-ico { -webkit-mask-image: var(--i-check); mask-image: var(--i-check); }
.btn-copy.is-copied { color: var(--ink); }
.btn-copy:hover { background: color-mix(in srgb, var(--code-bg), var(--text) 7%); }
/* The terracotta check on the hover tint is 4.2 to 4.4, so a copied control takes no tint. */
.btn-copy.is-copied:hover { background: transparent; }
@media (min-width: 32.51em) {
  .btn-copy { margin: 1px 1px 1px 0; padding: 0 18px; border: 0; border-left: 1px solid var(--line); border-radius: 0 11px 11px 0; }
  .btn-copy:focus-visible { outline-offset: -3px; }
}
@media (max-width: 32.5em) {
  .btn-copy { width: 44px; height: 44px; margin: 4px 4px 4px 0; padding: 0; border: 1px solid var(--control); border-radius: 8px; align-self: center; }
  .btn-copy .copy-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .btn-copy.is-copied { border-color: var(--ink); }
}
.btn-s { min-height: 44px; padding: 0 18px; border-color: var(--control); background: transparent; color: var(--text); font-size: .9375rem; font-weight: 500; }
.btn-s:hover:not(:disabled) { border-color: var(--ink); }
.btn-s:disabled { opacity: .6; cursor: default; }
.actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin: 2.25rem 0 0; }

/* ---------- hero ----------
   Centred: the cat, four coat chips, a two-line headline, one line, Download
   and the install line, on the night horizon. The top padding keeps the notch
   and the header pills clear. Without script the cat is a still picture and
   the chips are not shown. */
.hero { position: relative; display: flex; align-items: center; justify-content: center; min-height: min(100vh, 62rem); min-height: min(100svh, 62rem); padding-block: clamp(6.5rem, 14vh, 8.5rem) clamp(4rem, 9vh, 6rem); text-align: center; overflow-x: clip; }
html:not(.js) .hero { min-height: 0; }
.hero-inner { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; }
.hero-title .l { display: block; }
.hero-line { max-width: 34rem; margin: 1.5rem 0 0; font-size: clamp(1.125rem, 1rem + .5vw, 1.3125rem); line-height: 1.5; color: var(--text-2); }
.hero-cmd { width: min(100%, 49rem); margin-top: 1.25rem; text-align: left; }
/* The horizon: a big dark disc whose rim glows terracotta (a pale sun in the
   light theme), clipped to the hero so it never causes overflow. */
.horizon-clip { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.horizon { position: absolute; left: 50%; bottom: -78vw; width: 150vw; height: 86vw; translate: -50% 0; border-radius: 50%; background: radial-gradient(closest-side, #1A1215 96%, rgba(26, 18, 21, 0) 100%); box-shadow: 0 -2px 0 rgba(226, 104, 60, .5), 0 -26px 110px rgba(226, 104, 60, .26); }
html[data-theme="light"] .horizon { background: radial-gradient(closest-side, #FFE9CF 55%, rgba(255, 233, 207, 0) 100%); box-shadow: 0 -2px 0 rgba(224, 140, 90, .35), 0 -26px 110px rgba(246, 181, 142, .4); }

/* The cat: logo geometry in a 256 grid. Pieces are separate so the ears can
   twitch, the eyes follow the pointer, and the eyes swap for the happy and
   squint shapes. Colours come from the coat variables on <html>. */
.cat-wrap { position: relative; width: clamp(128px, 36vw, 164px); aspect-ratio: 1; margin-bottom: 6px; }
.stage { position: relative; width: 100%; height: 100%; z-index: 5; -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.js .stage { cursor: grab; }
.stage.is-held { cursor: grabbing; z-index: 95; }
.hero-inner.is-carrying { z-index: 95; }
.stage:focus-visible { outline: 3px solid var(--focus); outline-offset: 6px; border-radius: 24px; }
.cat { display: block; width: 100%; height: 100%; overflow: visible; }
.cat .ear { transform-box: fill-box; transition: transform .3s cubic-bezier(.3, 1.6, .5, 1); }
.cat .el { transform-origin: 100% 100%; }
.cat .er { transform-origin: 0 100%; }
.stage:hover .el { transform: rotate(-7deg); }
.stage:hover .er { transform: rotate(7deg); }
.cat .eye { transform-box: fill-box; transform-origin: center; transition: transform .09s; }
.cat.blink .eye { transform: scaleY(.12); }
.cat .happy, .cat .squint { opacity: 0; }
.cat.purr .eyes, .cat.is-held .eyes { opacity: 0; }
.cat.purr .happy { opacity: 1; }
.cat.is-held .squint { opacity: 1; }
.cat.purr { animation: purr .12s linear infinite; }
@keyframes purr { 50% { translate: 1.5px 0; } }
.bubble { position: absolute; left: 62%; top: -22px; z-index: 6; margin: 0; padding: 6px 12px; border-radius: 14px 14px 14px 4px; background: var(--bubble-bg); color: var(--bubble-text); font-weight: 600; font-size: .875rem; line-height: 1.4; white-space: nowrap; opacity: 0; transform: translateY(8px) scale(.8); transform-origin: 0 100%; transition: opacity .25s, transform .25s cubic-bezier(.3, 1.6, .5, 1); pointer-events: none; }
.bubble.on { opacity: 1; transform: none; }
.fx { position: absolute; left: 50%; top: 50%; z-index: 6; pointer-events: none; font-size: 18px; line-height: 1; color: var(--ink); }

.coats { display: flex; gap: 4px; justify-content: center; margin: 0 0 1.5rem; }
.coat-chip { position: relative; width: 36px; height: 36px; padding: 0; border: 0; border-radius: 50%; background: transparent; cursor: pointer; }
.coat-chip i { position: absolute; inset: 5px; border-radius: 50%; border: 1px solid var(--control); }
.coat-chip[aria-pressed="true"]::after { content: ""; position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--text); }
.coat-chip[data-coat="terracotta"] i { background: #E2683C; }
.coat-chip[data-coat="calico"] i { background: conic-gradient(#F4EDE4 0 50%, #E2683C 0 75%, #2B2420 0); }
.coat-chip[data-coat="white"] i { background: #F6F1EA; }
.coat-chip[data-coat="black"] i { background: #1E1B22; border-color: #75675B; }

/* ---------- marquee ----------
   The 14 page names, moved sideways by scroll (site.js). Static without
   script or with reduced motion; clipped, so it never causes overflow. */
.marquee { overflow: hidden; padding: 26px 0; border-block: 1px solid rgba(244, 237, 228, .06); background: rgba(18, 14, 16, .45); -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); }
html[data-theme="light"] .marquee { border-color: rgba(23, 18, 15, .08); background: rgba(255, 253, 249, .5); }
.marquee-row { display: flex; gap: 44px; width: max-content; font-size: clamp(1.625rem, 3.6vw, 2.5rem); font-weight: 600; letter-spacing: -.03em; line-height: 1.2; will-change: transform; }
.marquee-row span { display: flex; align-items: center; gap: 44px; color: rgba(244, 237, 228, .46); white-space: nowrap; }
.marquee-row span:nth-child(3n + 1) { color: var(--text); }
.marquee-row span::after { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--ink); }
html[data-theme="light"] .marquee-row span { color: rgba(23, 18, 15, .58); }
html[data-theme="light"] .marquee-row span:nth-child(3n + 1) { color: var(--text); }

/* ---------- story: one hover, fourteen pages ----------
   Without script, with reduced motion, or when the stage does not fit the
   viewport: static. The first page shows on the screen and the 14 pages are
   a readable list. site.js adds .is-pin when motion is welcome and the stage
   fits 100svh: the wrapper is tall, the stage sticks, and scroll progress
   grows the panel from notch size and flips through the pages. */
.story { padding-top: clamp(3rem, 8vw, 6rem); }
.story-grid { display: grid; gap: 1.5rem 3rem; grid-template-columns: minmax(0, 1fr); grid-template-areas: "copy" "visual" "list"; }
.story-copy { grid-area: copy; min-width: 0; }
.story-list { grid-area: list; min-width: 0; margin: 0; padding: 0; list-style: none; display: grid; gap: 0 2rem; grid-template-columns: minmax(0, 1fr); }
.story-visual { grid-area: visual; min-width: 0; }
@media (min-width: 40em) { .story-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 56.25em) {
  .story-grid { grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); grid-template-areas: "copy visual" "list visual"; grid-template-rows: auto 1fr; align-items: start; }
  .story-list { grid-template-columns: minmax(0, 1fr); }
}
.story-list li { padding: .7rem 0; border-top: 1px solid var(--line); line-height: 1.45; }
.story-list b { display: block; color: var(--text); font-weight: 600; }
.story-list span { color: var(--text-2); font-size: .9375rem; }
.story-count, .story-now, .story-bar { display: none; }
.story-count { margin-bottom: 14px; font-family: var(--mono); font-size: .8125rem; color: var(--ink-hi); }
.story-now { min-height: 5.5rem; }
.st-name { min-height: 2.25rem; font-size: 1.75rem; font-weight: 600; letter-spacing: -.02em; line-height: 1.2; color: var(--ink-hi); }
.st-line { max-width: 24em; min-height: 3rem; margin: 6px 0 26px; font-size: 1rem; line-height: 1.5; color: var(--text-2-hi); }
.story-bar { max-width: 320px; height: 2px; border-radius: 2px; background: var(--line); }
.story-bar i { display: block; height: 100%; width: calc(var(--sp, 0) * 100%); border-radius: 2px; background: var(--ink); }
.story-copy h2 { margin-bottom: 1.25rem; }
.js .st-name, .js .st-line { transition: opacity .2s, transform .2s; }
.story-copy.swap .st-name, .story-copy.swap .st-line { opacity: 0; transform: translateY(6px); }

.story.is-pin .story-pin { height: 560vh; }
@media (max-width: 40em) { .story.is-pin .story-pin { height: 420vh; } }
.story.is-pin .story-stage { position: sticky; top: 0; height: 100vh; height: 100svh; display: flex; flex-direction: column; justify-content: center; padding-block: 5rem 2rem; }
@media (max-width: 32.5em) { .story.is-pin .story-stage { padding-block: 4.5rem 1rem; } }
.story.is-pin .story-grid { grid-template-areas: "copy" "visual"; gap: 1.25rem; align-items: center; }
@media (min-width: 56.25em) { .story.is-pin .story-grid { grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); grid-template-areas: "copy visual"; grid-template-rows: auto; gap: 3.5rem; } }
.story.is-pin .story-count, .story.is-pin .story-now, .story.is-pin .story-bar { display: block; }
.story.is-pin .story-copy h2 { margin-bottom: 1.5rem; font-size: clamp(2rem, 1.25rem + 2.4vw, 3.5rem); }
.story.is-pin .story-list { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
@media (max-width: 56.24em) {
  /* Two lines reserved: a one-line description must not shorten the copy block,
     or the centred stage re-centres and the screen jumps on every page change. */
  .story.is-pin .st-line { margin-bottom: 14px; min-height: 3em; }
  .story.is-pin .story-now { min-height: 0; }
  .story.is-pin .story-copy h2 { margin-bottom: .75rem; font-size: clamp(1.75rem, 1rem + 3vw, 2.25rem); }
  .story.is-pin .story-count { margin-bottom: 8px; }
  .story.is-pin .st-name { font-size: 1.375rem; min-height: 0; }
}

/* The screen: a wallpaper, two windows, and the panel growing from the notch. */
.screen { --z: 1; position: relative; aspect-ratio: 16 / 10; width: 100%; max-width: 40rem; margin-inline: auto; padding: 8px; border: 1px solid var(--scr-edge); border-radius: 18px; background: var(--scr-bg); box-shadow: 0 50px 120px -40px rgba(0, 0, 0, .9); transform: scale(calc(.86 + var(--z) * .14)); }
html[data-theme="light"] .screen { box-shadow: 0 30px 80px -30px rgba(40, 24, 16, .45); }
.wall { position: relative; height: 100%; overflow: hidden; border-radius: 12px; background: radial-gradient(90% 80% at 20% 100%, #5A2638 0, transparent 60%), radial-gradient(80% 70% at 90% 10%, #9A4426 0, transparent 55%), linear-gradient(160deg, #241A18, #100C0C); }
.wall::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 9%; background: rgba(18, 14, 12, .72); border-top: 1px solid rgba(244, 237, 228, .06); }
.story .win { position: absolute; border-radius: 8px; background: rgba(30, 24, 21, .8); border: 1px solid rgba(244, 237, 228, .08); }
.story .win::before { content: ""; position: absolute; left: 10px; top: 9px; width: 30%; height: 6px; border-radius: 3px; background: rgba(244, 237, 228, .12); }
.win-a { left: 6%; top: 58%; width: 40%; height: 30%; }
.win-b { left: 62%; top: 62%; width: 32%; height: 26%; }
.bigpanel { position: absolute; top: 0; left: 50%; translate: -50% 0; z-index: 2; display: flex; flex-direction: column; width: min(560px, 88%); height: 72%; padding: 12px 18px; border: 1px solid var(--notch-edge); border-top: 0; border-radius: 0 0 26px 26px; background: #17120F; color: var(--scr-text); font-size: .8125rem; transform-origin: 50% 0; transform: scale(calc(.35 + var(--z) * .65), calc(.14 + var(--z) * .86)); }
.bp-top { display: flex; align-items: center; gap: 10px; font-size: .875rem; }
.bp-top .clk { margin-left: auto; font: 12px var(--mono); color: var(--scr-2); }
.bp-pages { position: relative; flex: 1; margin: 10px 0; opacity: var(--z); }
.bp-pg { position: absolute; inset: 0; visibility: hidden; opacity: 0; transform: translateX(24px); transition: opacity .3s, transform .35s cubic-bezier(.2, .8, .2, 1), visibility 0s .35s; font-size: .84375rem; }
.bp-pg.on { visibility: visible; opacity: 1; transform: none; transition-delay: 0s; }
.bp-pg.prev { transform: translateX(-24px); }
.bp-pg .r { display: flex; gap: 14px; padding: 7px 0; border-bottom: 1px solid rgba(244, 237, 228, .06); }
.bp-pg .r span { flex: none; width: 64px; color: var(--scr-2); font: 12px var(--mono); }
.bp-pg .m { display: flex; align-items: center; gap: 12px; padding: 6px 0; }
.bp-pg .m span { width: 96px; color: var(--scr-2); }
.bp-pg .m i { position: relative; flex: 1; height: 6px; overflow: hidden; border-radius: 3px; background: rgba(244, 237, 228, .1); }
.bp-pg .m i::after { content: ""; position: absolute; inset: 0; width: var(--v); border-radius: 3px; background: #E2683C; }
.bp-pg .tl { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.bp-pg .tl div { padding: 10px 12px; border-radius: 12px; background: #211A17; }
.bp-pg .tl b { display: block; font-size: .8125rem; }
.bp-pg .tl span { color: var(--scr-2); font-size: .75rem; }
.bp-pg .big { display: flex; align-items: center; gap: 18px; }
.bp-pg .big b { display: block; font-size: 1.375rem; }
.bp-pg .big span { color: var(--scr-2); }
.bp-pg .big > div { flex: 1; min-width: 0; }
.bp-pg .cv { flex: none; width: 84px; height: 84px; border-radius: 16px; background: linear-gradient(135deg, #E2683C, #7A2E45); }
.bp-pg .bar-w { width: 220px; max-width: 100%; margin-top: 10px; }
.bp-pg code { font: 12px var(--mono); line-height: 1.8; color: var(--scr-text); }
.bp-pg .pr { color: #E2683C; }
.bp-dock { display: flex; align-items: flex-end; justify-content: center; gap: 6px; height: 34px; opacity: var(--z); }
.bp-dock svg { flex: none; width: 20px; height: 20px; color: var(--scr-2); transform-origin: 50% 100%; transform: scale(var(--s, 1)); }
.bp-dock svg.on { color: #E2683C; }
@media (max-width: 40em) {
  .screen { aspect-ratio: 5 / 4; padding: 5px; border-radius: 14px; }
  .bigpanel { width: 94%; height: 88%; padding: 8px 12px; border-radius: 0 0 18px 18px; }
  .bp-pg { font-size: .75rem; }
  .bp-pg .r { padding: 4px 0; gap: 8px; }
  .bp-pg .r span { width: 54px; }
  .bp-pg .m { gap: 8px; padding: 4px 0; }
  .bp-pg .m span { width: 84px; }
  .bp-pg .big { gap: 10px; }
  .bp-pg .big b { font-size: 1.0625rem; }
  .bp-pg .cv { width: 52px; height: 52px; border-radius: 10px; }
  .bp-pg .big svg { width: 64px; height: 64px; }
  .bp-pg .tl div { padding: 6px 8px; }
  .bp-dock { gap: 2px; height: 28px; }
  .bp-dock svg { width: 15px; height: 15px; }
  .bp-top { font-size: .8125rem; }
}
@media (max-width: 24em) { .screen { aspect-ratio: 10 / 9; } }

/* ---------- playground ---------- */
.play { padding-block: clamp(5rem, 11vw, 8rem) clamp(3rem, 7vw, 5rem); }
.play h2 { margin-bottom: .875rem; text-align: center; }
.sub { max-width: 34em; margin: 0 auto clamp(2.25rem, 6vw, 3.5rem); font-size: 1.125rem; color: var(--text-2); text-align: center; }
.play-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 40em) { .play-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 60em) { .play-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.play-card { display: flex; flex-direction: column; min-width: 0; overflow: hidden; border: 1px solid var(--line); border-radius: 24px; background: var(--card); }
.play-pic { position: relative; flex: none; height: 190px; overflow: hidden; background: radial-gradient(90% 90% at 20% 110%, #4A2030 0, transparent 60%), radial-gradient(70% 70% at 95% 0, #7A3A22 0, transparent 60%), #120E0E; color: var(--scr-text); }
.play-body { display: flex; flex: 1; flex-direction: column; gap: 8px; padding: 20px 22px 22px; }
.play-body h3 { font-size: 1.1875rem; font-weight: 600; }
.play-body p { flex: 1; margin: 0; font-size: .90625rem; line-height: 1.5; color: var(--text-2); }
.ctl { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
/* The mini notch inside a picture. */
.mn { position: absolute; top: 0; left: 50%; translate: -50% 0; display: flex; align-items: center; gap: 8px; width: var(--w, 150px); height: var(--h, 30px); max-width: calc(100% - 16px); overflow: hidden; padding: 0 12px; border: 1px solid #75675B; border-top: 0; border-radius: 0 0 16px 16px; background: #17120F; color: #F4EDE4; font: 11px var(--mono); transition: width .45s cubic-bezier(.3, 1.3, .5, 1), height .45s cubic-bezier(.3, 1.3, .5, 1), border-radius .45s; }
.mn svg { flex: none; }
.clk { font: 11px var(--mono); color: #A89A8B; }
.mn-wide { --w: 230px; --h: 34px; }
/* dance */
.mn .lyric { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 500 11px var(--font); }
.mn .eq { flex: none; display: flex; align-items: flex-end; gap: 2px; height: 14px; }
.mn .eq i { display: block; width: 3px; height: 100%; border-radius: 2px; background: #E2683C; transform-origin: 50% 100%; transform: scaleY(.5); animation: eq .9s ease-in-out infinite alternate paused; }
.mn .eq i:nth-child(2) { animation-delay: -.3s; transform: scaleY(.85); }
.mn .eq i:nth-child(3) { animation-delay: -.6s; transform: scaleY(.6); }
.mn .eq i:nth-child(4) { animation-delay: -.15s; transform: scaleY(1); }
@keyframes eq { from { transform: scaleY(.22); } to { transform: scaleY(1); } }
.play-card.is-on .eq i { animation-play-state: running; }
.dance-cat { position: absolute; left: 50%; bottom: -18px; width: 120px; height: 120px; translate: -50% 0; transform-origin: 50% 100%; }
.play-card.is-on .dance-cat { animation: nod .5s ease-in-out infinite; }
@keyframes nod { 30% { transform: translateY(2px) rotate(-6deg); } 60% { transform: translateY(-1px) rotate(5deg); } }
.note { position: absolute; top: 40px; left: 50%; font-size: 16px; line-height: 1; color: #E2683C; pointer-events: none; }
/* typing */
.mn-type { justify-content: space-between; }
.mn-type .ti { display: flex; align-items: center; justify-content: space-between; width: 100%; }
.mn-type .tw, .mn-type .td { display: none; align-items: center; gap: 8px; font: 12px var(--font); width: 100%; }
.play-card[data-s="work"] .mn-type { --w: 200px; }
.play-card[data-s="done"] .mn-type { --w: 250px; --h: 40px; }
.play-card[data-s="work"] .mn-type .ti, .play-card[data-s="done"] .mn-type .ti { display: none; }
.play-card[data-s="work"] .mn-type .tw, .play-card[data-s="done"] .mn-type .td { display: flex; }
.td b { font-weight: 600; font-size: 12px; white-space: nowrap; }
.td .open { margin-left: auto; padding: 4px 10px; border-radius: 999px; background: #E2683C; color: #17120F; font-weight: 600; font-size: 11px; }
.paw { transform-box: fill-box; animation: paw .18s ease-in-out infinite alternate; }
.paw2 { animation-delay: -.09s; }
@keyframes paw { to { transform: translateY(-3px); } }
.dots { white-space: nowrap; }
.dots::after { content: ""; animation: dots 1.2s steps(4) infinite; }
@keyframes dots { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } }
.term-lines { position: absolute; left: 18px; right: 18px; bottom: 14px; font: 11px var(--mono); line-height: 1.6; color: rgba(244, 237, 228, .7); }
/* peek */
.play-card[data-card="peek"] .play-pic { cursor: crosshair; }
.play-pic .full { position: absolute; left: 10px; right: 10px; top: 10px; bottom: 0; border-radius: 10px 10px 0 0; background: #211A17; border: 1px solid rgba(244, 237, 228, .07); }
.play-pic .full::before { content: ""; position: absolute; left: 14px; top: 14px; width: 40%; height: 7px; border-radius: 4px; background: rgba(244, 237, 228, .1); }
.play-pic .full::after { content: ""; position: absolute; left: 14px; top: 34px; right: 30%; height: 60px; border-radius: 6px; background: repeating-linear-gradient(rgba(244, 237, 228, .06) 0 6px, transparent 6px 14px); }
.mn-peek { z-index: 2; }
.mn-peek .pi { display: flex; align-items: center; justify-content: space-between; width: 100%; }
.mn-peek .pe { display: none; gap: 10px; margin: 0 auto; }
.mn-peek .pe i { display: block; width: 7px; height: 12px; border-radius: 4px; background: #E2683C; transition: transform .08s; }
.play-card.is-eyes .mn-peek { --w: 58px; --h: 22px; padding: 0 12px; border-radius: 0 0 12px 12px; }
.play-card.is-eyes .mn-peek .pi { display: none; }
.play-card.is-eyes .mn-peek .pe { display: flex; }
.play-card.is-blink .pe i { transform: scaleY(.15) !important; }
/* susun */
.mn-susun { justify-content: center; font-family: var(--font); font-size: 12px; }
.play-pic .win { position: absolute; border-radius: 6px; background: rgba(30, 24, 21, .85); border: 1px solid rgba(244, 237, 228, .16); transition: left .5s cubic-bezier(.3, 1.2, .5, 1), top .5s cubic-bezier(.3, 1.2, .5, 1), width .5s cubic-bezier(.3, 1.2, .5, 1), height .5s cubic-bezier(.3, 1.2, .5, 1); }
.play-pic .win::before { content: ""; position: absolute; left: 10px; top: 9px; width: 30%; height: 6px; border-radius: 3px; background: rgba(244, 237, 228, .14); }
.lay button { width: 48px; height: 44px; padding: 6px 7px; border: 1px solid var(--control); border-radius: 10px; background: transparent; color: var(--text-2); cursor: pointer; }
.lay button[aria-pressed="true"] { border-color: var(--ink); color: var(--ink); }
.lay button:hover { border-color: var(--ink); }
.lay svg { display: block; width: 100%; height: 100%; }
/* draw */
.play-card[data-card="draw"] .play-pic { cursor: crosshair; }
.frozen { position: absolute; inset: 0; background: rgba(10, 8, 8, .45); }
.sel { position: absolute; left: 12%; top: 22%; width: 76%; height: 54%; border: 1.5px dashed rgba(244, 237, 228, .7); background: radial-gradient(90% 90% at 20% 110%, #5A2638 0, transparent 60%), #1A1414; }
.js .sel { touch-action: none; }
.sel::before { content: "640 x 360"; position: absolute; left: 0; top: -20px; padding: 2px 6px; border-radius: 4px; background: #17120F; color: #F4EDE4; font: 10px var(--mono); }
.draw-cv { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.tools { position: absolute; left: 50%; bottom: 8px; translate: -50% 0; z-index: 2; display: flex; gap: 4px; padding: 4px; border: 1px solid var(--scr-edge); border-radius: 12px; background: #17120F; }
.tools button { min-width: 44px; height: 36px; padding: 0 10px; border: 0; border-radius: 8px; background: transparent; color: #A89A8B; font: inherit; font-size: .8125rem; cursor: pointer; }
.tools button[aria-pressed="true"] { background: rgba(226, 104, 60, .22); color: #F4EDE4; }
.tools button:hover { color: #F4EDE4; }
/* copy */
.play-card[data-card="copy"] .play-pic { display: grid; place-items: center; padding: 30px 24px 20px; }
.play-pic blockquote { margin: 0; font-size: 1.0625rem; line-height: 1.45; font-weight: 500; text-align: center; user-select: text; -webkit-user-select: text; }
.play-pic blockquote::selection, .play-pic blockquote *::selection { background: rgba(226, 104, 60, .55); }
.play-pic kbd { padding: 1px 6px; border: 1px solid #75675B; border-radius: 6px; font: 12px var(--mono); color: #F4EDE4; }

/* ---------- install, Google Calendar, privacy ----------
   On a tint panel, so their text never sits straight on the dawn glow. */
.tint-panel { margin-top: clamp(3rem, 8vw, 6rem); border-top: 1px solid var(--line); background: var(--panel); padding-bottom: 1px; }
main > .tint-panel:last-child { margin-bottom: calc(-1 * clamp(4rem, 10vw, 8rem)); }
.gcal, .privacy-short, .install { padding-top: clamp(3.5rem, 8vw, 6rem); }
.privacy-short { padding-bottom: clamp(3rem, 7vw, 5rem); }
/* The last section: with the footer it is at least a screen less the 5rem scroll margin, so #privacy can scroll up to 80 px from the top. */
.privacy-short { min-height: calc(100vh - 18rem); min-height: calc(100svh - 18rem); }
.gcal h2, .privacy-short h2, .install h2 { margin-bottom: 1.25rem; }
.gcal .lead, .privacy-short .lead, .install .lead { color: var(--text); }
.install-dl { margin: 1.75rem 0 1rem; }
.gcal h3, .privacy-short h3, .install h3 { margin: 1.75rem 0 .6rem; font-size: 1.125rem; }
.scopes { margin: 0; }
.scopes dt { margin-top: 1rem; }
.scopes dt code { display: inline-block; max-width: 100%; padding: .35rem .6rem; background: var(--code-bg); border: 1px solid var(--line); border-radius: 6px; font-size: .8125rem; overflow-wrap: anywhere; }
.scopes dd { margin: .4rem 0 0; color: var(--text-2); }
.plain { margin: 0 0 1.25rem; padding: 0; list-style: none; }
.plain li { padding: .75rem 0; border-top: 1px solid var(--line); }
.plain li:last-child { border-bottom: 1px solid var(--line); }

/* Native disclosure: opens without script, the marker stays. */
.more { margin-top: 1.75rem; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.more summary { display: list-item; min-height: 44px; padding: .65rem 0; font-weight: 500; color: var(--text); cursor: pointer; }
.more summary:hover { color: var(--ink); }
.more summary::marker { color: var(--ink); }
.more-body { padding: .25rem 0 1.25rem; color: var(--text-2); }
.more-body p, .more-body dd { max-width: 40rem; }
.more-body h3 { color: var(--text); }
.more-body > :first-child { margin-top: 0; }

/* A command box: one 52 px box (the ::before, row 1 across both columns) with
   the scrolling command in column 1 and the Copy control in column 2, both
   drawn above it. Without script the Copy control is hidden and the command
   spans the box. The scrollbar is hidden; a right-edge fade (.is-fade, set by
   site.js only while the command is cut off and not scrolled to its end)
   shows there is more. Without script there is no fade, because overflow
   cannot be detected. The error message sits below the box (row 2). */
.cmd { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0; }
.cmd::before { content: ""; grid-area: 1 / 1 / 2 / -1; background: var(--code-bg); border: 1px solid var(--line); border-radius: 12px; }
.cmd-scroll { grid-area: 1 / 1; position: relative; display: flex; align-items: center; min-width: 0; min-height: 52px; padding: 0 16px; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
.cmd-scroll::-webkit-scrollbar { display: none; }
.cmd-scroll.is-fade { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent); }
.cmd-scroll code { font-size: .875rem; color: var(--text); user-select: text; }
.cmd > .btn-copy { grid-area: 1 / 2; position: relative; }
/* The mask would clip the scroll area's own focus ring, so the box wears it. */
@supports selector(:has(a)) {
  .cmd-scroll:focus-visible { outline: none; }
  .cmd:has(> .cmd-scroll:focus-visible)::before { outline: 3px solid var(--focus); outline-offset: 2px; }
}
.copy-msg { grid-area: 2 / 1 / 3 / -1; font-size: .875rem; }
.copy-msg:not(.is-error) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.copy-msg.is-error { margin-top: 8px; color: var(--ink); font-weight: 500; }

/* ---------- scroll reveal (headings and the playground cards only) ----------
   Once only, in every browser: site.js adds .is-in the first time the element
   is on screen and stops watching it, so it never replays on scroll back. The
   hiding rule exists only under .js; site.js adds .is-in to everything already
   in view at start. The head script drops .js at DOMContentLoaded if site.js
   failed (deferred scripts run before it), and adds .reveal-off after 4 s if
   site.js is merely slow, so the text shows without the layout switching. */
.js .reveal:not(.is-in) { opacity: 0; transform: translateY(16px); }
.js .reveal { transition: opacity .5s ease-out, transform .5s ease-out; }
@media (min-width: 60em) {
  .js .play-card.reveal:nth-child(3n + 2) { transition-delay: 60ms; }
  .js .play-card.reveal:nth-child(3n + 3) { transition-delay: 120ms; }
}
.js.reveal-off .reveal, .js.reveal-off .reveal:not(.is-in) { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal, .js .reveal:not(.is-in) { opacity: 1; transform: none; transition: none; }
}

/* ---------- the walking cat ----------
   Index only, made by site.js: a 3 px trail at the very bottom and a 30 px cat
   head that walks along it with page progress. Its track ends 12 px before the
   go-to-top tail's box (the tail is flush at the right edge, so that is the
   viewport width minus the box width, minus 12). At the end of the page it curls up and sleeps; asleep
   it is a real button that wakes it. */
.walk { position: fixed; left: 0; right: 0; bottom: 0; z-index: 70; height: 3px; pointer-events: none; }
.walk-trail { position: absolute; left: 0; bottom: 0; height: 3px; width: 0; background: linear-gradient(90deg, transparent, var(--ink)); }
.walk-pos { position: absolute; left: 0; bottom: 0; width: 30px; height: 33px; will-change: transform; }
.walk-cat { position: absolute; left: 0; bottom: 2px; width: 30px; height: 30px; margin: 0; padding: 0; border: 0; background: transparent; pointer-events: none; }
.walk-cat svg { display: block; width: 30px; height: 30px; overflow: visible; transform-origin: 50% 100%; }
.walk-cat.is-walking svg { animation: bob .4s ease-in-out infinite alternate; }
@keyframes bob { to { translate: 0 -3px; } }
.walk-cat.is-asleep { pointer-events: auto; cursor: pointer; }
.walk-cat.is-asleep svg { transform: translateY(3px) scale(1.08, .8) rotate(-5deg); }
.walk-cat:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; border-radius: 8px; }
.walk-cat.is-stretch svg { animation: stretch .5s ease-out; }
@keyframes stretch { 0% { transform: translateY(3px) scale(1.08, .8) rotate(-5deg); } 50% { transform: scale(.86, 1.3); } 100% { transform: none; } }
.walk-cat.is-dash svg { animation: bob .12s ease-in-out infinite alternate; transform: rotate(-10deg); }
.walk-bubble { position: absolute; right: -4px; bottom: 38px; margin: 0; padding: 5px 11px; border-radius: 12px 12px 4px 12px; background: var(--bubble-bg); color: var(--bubble-text); font-size: .8125rem; font-weight: 600; line-height: 1.4; white-space: nowrap; opacity: 0; transform: translateY(6px); transition: opacity .25s, transform .25s; pointer-events: none; }
.walk-bubble.on { opacity: 1; transform: none; }
.walk-bubble.flip { right: auto; left: -4px; border-radius: 12px 12px 12px 4px; }
.zz { position: absolute; left: 20px; bottom: 28px; display: none; color: var(--ink); font-size: 12px; font-weight: 700; line-height: 1; pointer-events: none; }
.walk-pos.is-asleep .zz { display: block; animation: zz 2.4s ease-out infinite; }
.walk-pos.is-asleep .zz:nth-of-type(2) { animation-delay: -.8s; }
.walk-pos.is-asleep .zz:nth-of-type(3) { animation-delay: -1.6s; }
@keyframes zz { 0% { opacity: 0; transform: translate(0, 0) scale(.7); } 25% { opacity: 1; } 100% { opacity: 0; transform: translate(10px, -22px) scale(1.1); } }

/* ---------- 404 ---------- */
.lost { padding-block: clamp(6.5rem, 16vw, 11rem) 2rem; text-align: center; }
.lost .wrap { width: min(100% - 2 * var(--gutter), 40rem); padding: clamp(2rem, 6vw, 3.5rem) clamp(1.25rem, 4vw, 3rem); border: 1px solid var(--line); border-radius: 28px; background: var(--panel); }
.lost h1 { max-width: 12ch; margin-inline: auto; }
.lost p { max-width: 32rem; margin: 1.5rem auto 0; }
.lost .btn { margin-top: 1rem; }
.notch-static { pointer-events: none; }
/* Without script the header is static and unfolded, so below the fold its
   links would sit under the notch. */
@media (max-width: 48.99em) { html:not(.js) .notch-static { display: none; } }
.notch-static .nf { opacity: 1; justify-content: space-between; }
.notch-static .clock { color: var(--notch-2); }

/* ---------- legal pages ---------- */
.legal { padding-block: clamp(3rem, 7vw, 5.5rem) 0; }
/* With script the header is fixed over the page: start below its pills. */
.js .legal { padding-top: calc(4.5rem + clamp(1rem, 4vw, 3rem)); }
/* The text sits on a tint, never straight on the sky. */
.legal-doc { width: min(100% - 2 * var(--gutter), 78ch); margin-inline: auto; padding: clamp(1.25rem, 4vw, 3rem); border: 1px solid var(--line); border-radius: 28px; background: var(--panel); }
.legal-doc h1 { max-width: none; font-size: clamp(2.25rem, 1.4rem + 3.4vw, 3.75rem); line-height: 1; letter-spacing: -.04em; }
.legal-updated { margin: 1rem 0 2.5rem; color: var(--text-2); font-family: var(--mono); font-weight: 400; font-size: .875rem; }
.legal-summary { margin: 0 0 2.5rem; padding: 1.5rem 1.75rem; background: var(--bg-2); border: 1px solid var(--line); border-radius: 16px; }
.legal-summary h2 { margin: 0 0 .75rem; font-size: 1.25rem; letter-spacing: -.02em; }
.legal-summary > :last-child { margin-bottom: 0; }
.legal-summary ul { margin: 0; padding-left: 1.25rem; }
.legal-summary li { margin-bottom: .4rem; }
.legal-toc { margin: 0 0 3rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--line); }
.legal-toc ol { margin: 0; padding-left: 1.5rem; columns: 2 16rem; column-gap: 2rem; color: var(--text-2); }
.legal-toc li { margin-bottom: .25rem; break-inside: avoid; }
.legal-toc a { display: inline-block; padding: .7rem 0; }
.legal-doc section { margin-top: 3rem; }
.legal-doc h2 { margin: 0 0 1rem; font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.125rem); letter-spacing: -.03em; }
.legal-doc h3 { margin: 1.75rem 0 .5rem; font-size: 1.25rem; }
.legal-doc ul, .legal-doc ol { padding-left: 1.4rem; margin: 0 0 1em; }
.legal-doc li { margin-bottom: .4rem; }
.legal-doc p code, .legal-doc li code, .legal-doc td code, .legal-doc th code { padding: .1em .35em; background: var(--code-bg); border: 1px solid var(--line); border-radius: 4px; overflow-wrap: anywhere; word-break: break-word; }
.legal-quote { margin: 1.5rem 0; padding: 1rem 0 1rem 1.25rem; border-left: 2px solid var(--ink); font-size: 1.0625rem; }
.legal-quote > :last-child { margin-bottom: 0; }
.table-wrap { margin: 1.5rem 0; max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain; border: 1px solid var(--line); border-radius: 12px; }
.table-wrap table { width: 100%; min-width: 34rem; border-collapse: collapse; font-size: .9375rem; }
.table-wrap caption { padding: .75rem 1rem; text-align: left; font-weight: 600; caption-side: top; }
.table-wrap th, .table-wrap td { padding: .6rem 1rem; text-align: left; vertical-align: top; border-top: 1px solid var(--line); }
.table-wrap thead th { background: var(--bg-2); font-weight: 600; }

@media print {
  html::before, body::before, body::after, #sky, .walk { display: none !important; }
  html { background: #fff; }
  .notch, .skip, .menu-btn, .theme-btn, .to-top { display: none !important; }
  .js .site-header { position: static; }
  .story .story-pin { height: auto !important; }
  .story .story-stage { position: static !important; height: auto !important; }
}

/* Reduced motion: states still change, but at once. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .notch, .nf, .notch-panel { transition: none; }
  .eq i, .paw, .dots::after, .cat.purr, .play-card.is-on .dance-cat { animation: none !important; }
  .dots::after { content: "..."; }
  .cat .ear, .cat .eye, .bubble, .mn, .play-pic .win, .bp-pg, .walk-bubble, .mn-peek .pe i { transition: none; }
  .walk-cat svg, .zz { animation: none !important; }
  .walk-pos.is-asleep .zz { opacity: .9; }
  .marquee-row { transform: none !important; will-change: auto; }
  .screen, .bigpanel { transition: none; }
}

/* Links inside running text get a taller hit area (padding on an inline box does not move the lines). */
main p a, main dd a, main li a, .footer-brand a { padding-block: .75em; }
main .btn { padding-block: 0; }

/* ---------- phones (below 40em) ----------
   A 20 px gutter and header edge, full-width Download buttons, the install
   rhythm (h2 16 to the lead, the lead 28 to Download, Download 16 to the
   command box, the box 32 to the details, h3 32 above and 12 below), and 44 px
   targets for the coat chips, the draw tools and the footer licence link. From
   40em up none of this applies. The go-to-top tail keeps its own 16 px bottom gap. */
@media (max-width: 39.99em) {
  :root { --gutter: 20px; --edge: 20px; }
  .install h2, .gcal h2, .privacy-short h2 { margin-bottom: 16px; }
  .hero .actions { align-self: stretch; }
  .hero .actions .btn-primary, .install-dl .btn { width: 100%; }
  .install-dl .btn { display: flex; }
  .hero-cmd { margin-top: 16px; }
  .more { margin-top: 32px; }
  .gcal h3, .privacy-short h3, .install h3 { margin: 32px 0 12px; }
  .scopes dt:first-child { margin-top: 0; }
  .coats { gap: 0; }
  .coat-chip { width: 44px; height: 44px; }
  .coat-chip i { inset: 9px; }
  .coat-chip[aria-pressed="true"]::after { inset: 4px; }
  /* 44 px buttons in a bar with 2 px padding, 4 px up: the bar's top edge stays
     where it was (136 px in the 190 px picture), so it covers no more of the
     selection than before. */
  .tools { bottom: 4px; padding: 2px; }
  .tools button { height: 44px; }
  .footer-brand a { display: inline-block; padding-block: 0; min-height: 44px; line-height: 44px; vertical-align: middle; }
}
