/* robotpaper: light/dark theme (theme 1.10.0, Theme menu and the light accent in 1.11.0, square hit boxes in 1.11.2, 2026-10-24). The shared contract (sites-toggle SPEC.md):
   <html data-theme="light|dark"> forces a mode; no attribute = follow the OS (prefers-color-scheme).
   Set by the boot script (partials/rp-theme-head.hbs) and the Light/Dark/System control (partials/rp-theme-toggle.hbs,
   assets/rp/theme-toggle.js).

   How it works: Source styles everything with its --color-* variables and --background-color. This file
   1. gives the few things Source (and the robotpaper extras) colour with literals an --rp-* variable, whose LIGHT value
      is exactly what the page shows today, so light mode looks unchanged;
   2. defines the DARK values of all of them in ONE block, applied twice (an OS in dark mode unless the visitor chose
      Light, and the visitor's explicit Dark): keep the two copies identical.
   Linked in default.hbs AFTER Source's inline background-colour script, so that script still measures the configured
   site background colour (Design > Brand), not the dark one, and never sets has-light-text because of dark mode.
   Dark palette: Source's own ink (#15171a) becomes the page, text is a soft white; the accent stays Roy's accent
   (Ghost Admin), with a lighter tint of it for text links; the crimson of the logo/Markdown buttons gets lighter.
   AA: text >= 4.5:1, UI and large text >= 3:1 on the page and on the raised surfaces (see ROBOTPAPER.md). */

/* 1. Light values (= the look before 1.10.0) */
:root {
    color-scheme: light;
    --rp-surface: #fff;                         /* dropdown panels: Source's "more" menu, Sites by Roy */
    --rp-surface-text: #15171a;
    --rp-surface-shadow: 0 0 0 1px rgb(0 0 0 / 0.04), 0 7px 20px -5px rgb(0 0 0 / 0.15);
    /* Light-mode accent (1.11.0, Roy): Ghost Admin's accent #FF1A75 is 3.71:1 against white, below AA for white text on
       accent buttons (Subscribe, the signup card, Koenig buttons) and for accent links/tags. Light mode uses the same
       hue mixed with 15% black (#d91663, 4.95:1 with white); it is applied below on <body> as --ghost-accent-color, so
       Source, Koenig cards and the robotpaper partials all pick it up. Dark mode keeps the Admin accent as it is.
       A different Admin accent gets the same 15% treatment: re-check its contrast then. */
    --rp-accent-light: color-mix(in srgb, var(--ghost-accent-color) 85%, #000);
    --rp-on-accent: var(--color-white);         /* text on accent buttons (Subscribe, form buttons) */
    --rp-accent-text: var(--rp-accent-light);   /* accent as text: links in posts, captions, the post tag */
    --rp-form-hover: rgb(0 0 0 / 0.065);
    --rp-placeholder: rgb(0 0 0 / 0.3);
    --rp-share-text: rgb(0 0 0 / 0.85);         /* outlined buttons: Share, Markdown */
    --rp-share-border: rgb(0 0 0 / 0.15);
    --rp-share-border-hover: rgb(0 0 0 / 0.5);
    --rp-crimson: #c20820;                      /* the logo red: Markdown buttons, About page */
    --rp-crimson-soft: rgb(194 8 32 / 0.45);
    --rp-crimson-tint: rgb(194 8 32 / 0.06);
    --rp-charcoal: #2b2b2b;                     /* the logo charcoal: About page links */
    --rp-rule: rgb(43 43 43 / 0.1);
    --rp-rule-strong: rgb(43 43 43 / 0.14);
    --rp-muted: rgb(43 43 43 / 0.5);
    --rp-tile: #fff;                            /* About page icon tiles */
    --rp-media-backing: transparent;            /* behind images in posts (transparent PNGs) */
    --rp-toggle-on: rgb(0 0 0 / 0.06);          /* the pressed theme button */
    --rp-focus: var(--rp-accent-light);
    /* Prism (rp-prism.hbs loads prismjs 1.30.0 themes/prism.min.css): its light values */
    --rp-code-bg: #f5f2f0;
    --rp-code-text: #000;
    --rp-code-shadow: 0 1px #fff;
    --rp-code-comment: #708090;
    --rp-code-punct: #999;
    --rp-code-prop: #905;
    --rp-code-string: #690;
    --rp-code-operator: #9a6e3a;
    --rp-code-operator-bg: hsl(0 0% 100% / 0.5);
    --rp-code-keyword: #07a;
    --rp-code-function: #dd4a68;
    --rp-code-variable: #e90;
}

/* 2. Dark values: copy 1 of 2, the OS is dark and the visitor did not choose Light */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;
        --background-color: #15171a;
        --color-lighter-gray: rgb(255 255 255 / 0.07);
        --color-light-gray: #2b2e33;
        --color-mid-gray: #44484e;
        --color-dark-gray: #c5c8cc;
        --color-darker-gray: #e9eaec;
        --color-secondary-text: rgb(255 255 255 / 0.66);
        --color-border: rgb(255 255 255 / 0.13);
        --color-dark-border: rgb(255 255 255 / 0.5);
        --rp-surface: #22252a;
        --rp-surface-text: #e9eaec;
        --rp-surface-shadow: 0 0 0 1px rgb(255 255 255 / 0.1), 0 10px 28px -6px rgb(0 0 0 / 0.7);
        --rp-accent-light: var(--ghost-accent-color);  /* dark: the Admin accent unchanged */
        --rp-on-accent: #15171a;
        --rp-accent-text: color-mix(in srgb, var(--ghost-accent-color) 78%, #fff);
        --rp-form-hover: rgb(255 255 255 / 0.11);
        --rp-placeholder: rgb(255 255 255 / 0.45);
        --rp-share-text: rgb(255 255 255 / 0.88);
        --rp-share-border: rgb(255 255 255 / 0.25);
        --rp-share-border-hover: rgb(255 255 255 / 0.7);
        --rp-crimson: #ff5c70;
        --rp-crimson-soft: rgb(255 92 112 / 0.55);
        --rp-crimson-tint: rgb(255 92 112 / 0.1);
        --rp-charcoal: #e9eaec;
        --rp-rule: rgb(255 255 255 / 0.12);
        --rp-rule-strong: rgb(255 255 255 / 0.2);
        --rp-muted: rgb(255 255 255 / 0.6);
        --rp-tile: #fff;
        --rp-media-backing: #fff;
        --rp-toggle-on: rgb(255 255 255 / 0.12);
        --rp-focus: color-mix(in srgb, var(--ghost-accent-color) 78%, #fff);
        --rp-code-bg: #1f2227;
        --rp-code-text: #e3e5e8;
        --rp-code-shadow: none;
        --rp-code-comment: #9aa3ad;
        --rp-code-punct: #b4bac1;
        --rp-code-prop: #ff8fb1;
        --rp-code-string: #a8d58a;
        --rp-code-operator: #e6c07b;
        --rp-code-operator-bg: transparent;
        --rp-code-keyword: #7cc4ff;
        --rp-code-function: #ff9a8a;
        --rp-code-variable: #f5b86a;
    }
}

/* 2. Dark values: copy 2 of 2, the visitor chose Dark (keep identical to copy 1) */
:root[data-theme="dark"] {
    color-scheme: dark;
    --background-color: #15171a;
    --color-lighter-gray: rgb(255 255 255 / 0.07);
    --color-light-gray: #2b2e33;
    --color-mid-gray: #44484e;
    --color-dark-gray: #c5c8cc;
    --color-darker-gray: #e9eaec;
    --color-secondary-text: rgb(255 255 255 / 0.66);
    --color-border: rgb(255 255 255 / 0.13);
    --color-dark-border: rgb(255 255 255 / 0.5);
    --rp-surface: #22252a;
    --rp-surface-text: #e9eaec;
    --rp-surface-shadow: 0 0 0 1px rgb(255 255 255 / 0.1), 0 10px 28px -6px rgb(0 0 0 / 0.7);
    --rp-accent-light: var(--ghost-accent-color);  /* dark: the Admin accent unchanged */
    --rp-on-accent: #15171a;
    --rp-accent-text: color-mix(in srgb, var(--ghost-accent-color) 78%, #fff);
    --rp-form-hover: rgb(255 255 255 / 0.11);
    --rp-placeholder: rgb(255 255 255 / 0.45);
    --rp-share-text: rgb(255 255 255 / 0.88);
    --rp-share-border: rgb(255 255 255 / 0.25);
    --rp-share-border-hover: rgb(255 255 255 / 0.7);
    --rp-crimson: #ff5c70;
    --rp-crimson-soft: rgb(255 92 112 / 0.55);
    --rp-crimson-tint: rgb(255 92 112 / 0.1);
    --rp-charcoal: #e9eaec;
    --rp-rule: rgb(255 255 255 / 0.12);
    --rp-rule-strong: rgb(255 255 255 / 0.2);
    --rp-muted: rgb(255 255 255 / 0.6);
    --rp-tile: #fff;
    --rp-media-backing: #fff;
    --rp-toggle-on: rgb(255 255 255 / 0.12);
    --rp-focus: color-mix(in srgb, var(--ghost-accent-color) 78%, #fff);
    --rp-code-bg: #1f2227;
    --rp-code-text: #e3e5e8;
    --rp-code-shadow: none;
    --rp-code-comment: #9aa3ad;
    --rp-code-punct: #b4bac1;
    --rp-code-prop: #ff8fb1;
    --rp-code-string: #a8d58a;
    --rp-code-operator: #e6c07b;
    --rp-code-operator-bg: transparent;
    --rp-code-keyword: #7cc4ff;
    --rp-code-function: #ff9a8a;
    --rp-code-variable: #f5b86a;
}

/* The accent everything inside the page uses (Ghost puts the Admin accent on :root; --rp-accent-light is computed there,
   so this is not a cycle): light mode the darker one, dark mode the Admin accent (see --rp-accent-light) */
body {
    --ghost-accent-color: var(--rp-accent-light);
}

/* 3. Source literals -> variables (same light values as screen.css) */
.gh-button {
    color: var(--rp-on-accent);
}

/* Koenig accent buttons (cards.min.css: white text) follow the header's Subscribe button */
:root :is(.kg-button-card a.kg-btn-accent, .kg-product-card a.kg-product-card-btn-accent, .kg-header-card.kg-style-light a.kg-header-card-button) {
    color: var(--rp-on-accent);
}

/* The signup card's button gets its text colour as an inline style from the editor (white): dark mode only, the same
   dark text as the other accent buttons (light mode keeps the editor's colour) */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .kg-signup-card-button.kg-style-accent {
        color: var(--rp-on-accent) !important;
    }
}

:root[data-theme="dark"] .kg-signup-card-button.kg-style-accent {
    color: var(--rp-on-accent) !important;
}

.gh-button-share {
    color: var(--rp-share-text);
    border-color: var(--rp-share-border);
}

.gh-button-share:hover {
    border-color: var(--rp-share-border-hover);
}

.gh-content a,
figcaption a,
.gh-article-tag {
    color: var(--rp-accent-text);
}

.gh-form:hover {
    background-color: var(--rp-form-hover);
}

.gh-form-input::placeholder {
    color: var(--rp-placeholder);
}

.gh-dropdown {
    background-color: var(--rp-surface);
    box-shadow: var(--rp-surface-shadow);
}

.gh-dropdown li a {
    color: var(--rp-surface-text) !important;
}

/* Images in posts: a transparent PNG drawn for a white page keeps its white page (no effect on opaque images) */
.gh-content :is(.kg-image-card, .kg-gallery-image) img,
.kg-bookmark-icon {
    background-color: var(--rp-media-backing);
}

/* The wordmark logo (Ghost Admin > Design > Brand) is charcoal + crimson on transparent: in dark mode the same box
   shows assets/rp/robotpaper-wordmark-dark.png instead (soft white + a lighter crimson), as a background, with the
   original pushed out of view: the <img> and its alt text stay, so the header layout and the link name do not change.
   Only for that exact file: a new logo needs its own dark variant here. */
img[src$="/robotpaper-wordmark-header.png"] {
    background: var(--rp-logo-dark, none) center / contain no-repeat;
    object-position: var(--rp-logo-pos, 50% 50%);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) img[src$="/robotpaper-wordmark-header.png"] {
        --rp-logo-dark: url("robotpaper-wordmark-dark.png");
        --rp-logo-pos: -9999px 0;
    }
}

:root[data-theme="dark"] img[src$="/robotpaper-wordmark-header.png"] {
    --rp-logo-dark: url("robotpaper-wordmark-dark.png");
    --rp-logo-pos: -9999px 0;
}

/* 4. robotpaper extras with literal colours */
/* Markdown buttons (partials/ai-md-buttons.hbs is generated on the server from author.yaml: its inline <style> keeps the
   light literals, these win by specificity) */
:root .rp-md-msg {
    color: var(--rp-crimson);
}

:root .rp-md-block :is(button, .rp-md-nojs) {
    color: var(--rp-crimson);
    border-color: var(--rp-crimson-soft);
}

:root .rp-md-block button:hover {
    background: var(--rp-crimson-tint);
    border-color: var(--rp-crimson);
}

:root .rp-md :is(button, .rp-md-nojs):focus-visible {
    outline-color: var(--rp-crimson);
}

/* Prism syntax highlighting (loaded by rp-prism.hbs after this file: these selectors are more specific) */
:root :is(code, pre)[class*="language-"] {
    color: var(--rp-code-text);
    text-shadow: var(--rp-code-shadow);
}

:root pre[class*="language-"],
:root :not(pre) > code[class*="language-"] {
    background: var(--rp-code-bg);
}

:root .token:is(.comment, .prolog, .doctype, .cdata) { color: var(--rp-code-comment); }
:root .token.punctuation { color: var(--rp-code-punct); }
:root .token:is(.property, .tag, .boolean, .number, .constant, .symbol, .deleted) { color: var(--rp-code-prop); }
:root .token:is(.selector, .attr-name, .string, .char, .builtin, .inserted) { color: var(--rp-code-string); }
:root :is(.token:is(.operator, .entity, .url), .language-css .token.string, .style .token.string) {
    color: var(--rp-code-operator);
    background: var(--rp-code-operator-bg);
}
:root .token:is(.atrule, .attr-value, .keyword) { color: var(--rp-code-keyword); }
:root .token:is(.function, .class-name) { color: var(--rp-code-function); }
:root .token:is(.regex, .important, .variable) { color: var(--rp-code-variable); }

/* Header nav links (Ghost navigation: Home, About, ...): a 44px tall hit area without moving anything. The link becomes
   an inline-flex box at least --rp-nav-hit tall and --rp-nav-pad wider on each side, and equal negative margins give
   the extra size back, so its layout box stays the text's size: same header height, same spacing, same widths (Source's "..." overflow is unchanged).
   Items Source moves into its "..." dropdown keep the dropdown's own styles (only direct .nav > li > a). */
:root {
    --rp-nav-hit: 44px;
    --rp-nav-pad: 8px;  /* each side, also given back: the shortest item ("RSS", 29px) becomes 45px wide; nav gap is 28px */
}

.gh-navigation .nav > li > a {
    display: inline-flex;
    align-items: center;
    min-height: var(--rp-nav-hit);
    margin-block: calc((1lh - var(--rp-nav-hit)) / 2);
    padding-inline: var(--rp-nav-pad);
    margin-inline: calc(-1 * var(--rp-nav-pad));
}

/* Links in the desktop dropdown panels (Source's "..." overflow menu, where About can sit, and the Sites by Roy panel,
   which copies it): at least --rp-nav-hit tall, one under the other with no overlap. The panels get a little taller
   (rows of 44px instead of 36.5px); their width and which items Source moves into "..." do not change. */
@media (min-width: 768px) {
    .gh-navigation .gh-dropdown li a,
    .gh-navigation .sbr-menu .sbr-link {
        display: flex;
        align-items: center;
        min-height: var(--rp-nav-hit);
        padding-block: 4px;
    }
}

/* 5. The Light / Dark / System control (partials/rp-theme-toggle.hbs), in .gh-navigation-actions */
.theme-toggle {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: 2px;
    padding: 1px;
    border: 1px solid var(--color-border);
    border-radius: 999px;
}

.theme-toggle[hidden] {
    display: none;
}

.theme-toggle__btn {
    display: inline-flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    height: 44px;
    padding: 0 12px;
    font: inherit;
    font-size: 1.4rem;
    font-weight: 550;
    line-height: 1;
    color: var(--color-secondary-text);
    cursor: pointer;
    background: transparent;
    border: 0;
    border-radius: 999px;
    position: relative;
    z-index: 0;
}

/* Square hit boxes (1.11.2, SPEC 3b). A border-radius clips an element's own hit area, so points near the corners of a
   999px-radius button landed on the group or the popover behind it. Now:
   - ::after is the hit box: a transparent square exactly the button's size (a pseudo-element hit counts as the button;
     the button's radius does not clip it, overflow is visible), so all 4 corners hit the button;
   - ::before draws the round look (the pill fill and inset ring of the pressed choice) behind the icon and label
     (z-index -1 inside the button's own stacking context);
   - the button's own border-radius only shapes its focus outline, which stays the round ring it was (z-index 1 while
     focused, so the neighbouring choice can't cover it). Unfocused it paints nothing itself. */
.theme-toggle__btn::before,
.theme-toggle__btn::after {
    position: absolute;
    inset: 0;
    content: "";
}

.theme-toggle__btn::before {
    z-index: -1;
    border-radius: 999px;
    pointer-events: none;
}

.theme-toggle__btn svg {
    flex: none;
    width: 18px;
    height: 18px;
}

.theme-toggle__btn:hover {
    color: var(--color-darker-gray);
}

.theme-toggle__btn[aria-pressed="true"] {
    color: var(--color-darker-gray);
}

.theme-toggle__btn[aria-pressed="true"]::before {
    background: var(--rp-toggle-on);
    box-shadow: inset 0 0 0 1.5px var(--color-dark-border);
}

.theme-toggle__btn:focus-visible {
    z-index: 1;
    outline: 2px solid var(--rp-focus);
    outline-offset: 2px;
}

/* Desktop: icons only (the names stay for screen readers and in the tooltips) */
@media (min-width: 768px) {
    .gh-navigation-actions .theme-toggle__btn {
        width: 44px;
        padding: 0;
    }

    .gh-navigation-actions .theme-toggle__label {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
}

/* The Theme button (SPEC 3b) and its popover. Narrow desktop/tablet: Source keeps its one-row header down to 768px, but
   the 3-button group (168px with its gap) only fits next to search + Sign in + Subscribe where Source's middle-logo grid
   (1fr auto 1fr) still has equal side columns; anywhere tighter it narrows the nav column, and dropdown.js moves nav
   links into "..." (or the grid squeezes the logo). Source's side padding is max(4vmin, 20px), up to 4% of the width on
   a tall window, so that holds from about 1125px (home page, with the Markdown buttons: about 1345px). Below that, from
   768 to 1151px (home page: to 1351px), the inline group is hidden and one "Theme" icon button (rp-theme-menu.hbs,
   right after search) opens the group in a popover: the header keeps its 1.9.0 height (one 100px row) and, since
   1.11.1, the Theme button costs the row nothing (see "costs the row nothing" below), so the logo and the nav links
   are exactly 1.9.0's at every width and window height. Everywhere else the Theme button is hidden: phones have the
   inline group in the burger menu, wide screens in the header row. */
.theme-menu,
.theme-menu[hidden],
.theme-menu__panel[hidden] {
    display: none;
}

.theme-menu {
    position: relative;
    flex: none;
}

/* 44x44 hit area (the whole square: the round "open" background is a pseudo-element, so the corners still hit the
   button); -6px margins keep its layout box the 32px of Source's search button */
.theme-menu__btn.gh-icon-button {
    position: relative;
    width: 44px;
    height: 44px;
    margin: -6px;
}

.theme-menu__btn::before {
    position: absolute;
    inset: 0;
    content: "";
    border-radius: 999px;
    pointer-events: none;
}

.theme-menu__btn svg {
    position: relative;
    width: 20px;
    height: 20px;
}

.theme-menu__btn[aria-expanded="true"]::before {
    background: var(--rp-toggle-on);
}

.theme-menu__btn:focus-visible {
    outline: 2px solid var(--rp-focus);
    outline-offset: 2px;
}

.theme-menu__panel {
    position: absolute;
    top: calc(100% + 12px);
    inset-inline-end: -10px;
    z-index: 200;
    padding: 6px;
    color: var(--rp-surface-text);
    background-color: var(--rp-surface);
    border-radius: 12px;
    box-shadow: var(--rp-surface-shadow);
}

.theme-menu__panel .theme-toggle {
    border: 0;
    padding: 0;
}

.theme-menu__panel .theme-toggle__btn {
    padding: 0 12px;
}

/* the names are shown in the popover (the icon-only rule below is for the inline group in the header row) */
.gh-navigation-actions .theme-menu__panel .theme-toggle__btn {
    width: auto;
}

.gh-navigation-actions .theme-menu__panel .theme-toggle__label {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
}

/* The Theme button costs the row nothing (1.11.1). It sits right after search, and its 44x44 hit area exactly fills the
   space between the search button's box and Sign in (it touches both, overlapping neither): -20px/-22px margins on its
   32px layout box against Source's 28px gap, so the actions column gets 18px wider (1.11.0: 40px, which made
   dropdown.js move one more nav link into "..." than 1.9.0 at a few widths; 1.11.0 also switched to the inline group at
   1072px, home 1248px, where on a tall window it still cost a nav link). The same 18px are given back inside that
   column, in fixed px, so its min-content width (all the grid uses) equals 1.9.0's at every width and font:
     6px  the column may reach into the 24px gap next to the logo (only seen where the grid is tight: 18px are left),
     6px  of the 20px gap between Sign in and Subscribe,
     6px  of Subscribe's side padding (3px a side; 21px > 18px).
   So the menu, logo and nav columns are exactly 1.9.0's (no logo squeeze, the same nav items at every width). */
@media (min-width: 768px) and (max-width: 1151px) {
    #gh-navigation .gh-navigation-actions > .theme-toggle {
        display: none;
    }

    #gh-navigation .gh-navigation-actions > .theme-menu:not([hidden]) {
        display: block;
        margin-inline: -20px -22px;
    }

    #gh-navigation .gh-navigation-actions:has(> .theme-menu:not([hidden])) {
        margin-inline-start: -6px;
    }

    #gh-navigation .gh-navigation-actions:has(> .theme-menu:not([hidden])) > .gh-navigation-members {
        gap: 14px;
    }

    #gh-navigation .gh-navigation-actions:has(> .theme-menu:not([hidden])) > .gh-navigation-members .gh-button {
        padding-inline: calc(1.4em - 3px);
    }
}

@media (min-width: 1152px) and (max-width: 1351px) {
    #gh-navigation .gh-navigation-actions:has(> .rp-md-nav) > .theme-toggle {
        display: none;
    }

    #gh-navigation .gh-navigation-actions:has(> .rp-md-nav) > .theme-menu:not([hidden]) {
        display: block;
        margin-inline: -20px -22px;
    }

    #gh-navigation .gh-navigation-actions:has(> .rp-md-nav):has(> .theme-menu:not([hidden])) {
        margin-inline-start: -6px;
    }

    #gh-navigation .gh-navigation-actions:has(> .rp-md-nav):has(> .theme-menu:not([hidden])) > .gh-navigation-members {
        gap: 14px;
    }

    #gh-navigation .gh-navigation-actions:has(> .rp-md-nav):has(> .theme-menu:not([hidden])) > .gh-navigation-members .gh-button {
        padding-inline: calc(1.4em - 3px);
    }
}

/* Mobile: in the burger menu, above Sign in / Subscribe, with the names shown */
@media (max-width: 767px) {
    #gh-navigation .gh-navigation-actions > .theme-toggle {
        margin-bottom: 8px;
    }

    #gh-navigation .theme-toggle__btn {
        font-size: 1.5rem;
    }
}

@media (prefers-reduced-motion: no-preference) {
    .theme-toggle__btn {
        transition: color 0.15s;
    }

    .theme-toggle__btn::before {
        transition: background-color 0.15s;
    }
}
