/* ── Code ──────────────────────────────────────────────────────
   Inline code, fenced code blocks, and their syntax-highlighting
   token colors - one component, shared by the Content Editor's live
   preview and every public Markdown projection (Profile Sections,
   Articles, Projects, Offerings, and whatever long-form content comes
   after those). See ../README.md's "Code blocks" section for the
   rendering pipeline this markup comes from (apps.core.markdown +
   apps.core.highlighting) and ../tokens/colors.css's "Code: dark
   technical surface" for the theme itself (Issue 60): the site's own
   primary dark grey (--palette-dark-grey, the same one the footer
   terminates the page on) rather than a light sand panel, a boxed-in
   gray card, or a black terminal rectangle - a deliberate "white
   editorial page -> dark technical area" hierarchy, with a soft
   shadow and a barely-there hairline border (not a card outline -
   the dark fill already separates the block from the page on its
   own) to lift it off the surrounding prose.
   The language identifier is never shown as UI chrome (no
   "PYTHON"/"BASH" label) - only the Copy button sits in the corner,
   so a block reads as a clean editor pane, not a labelled snippet
   widget. It does one more quiet thing though: it picks which of a
   few restrained language-family palettes the block's syntax tokens
   render in (see "Language-aware overrides" and "Language-family
   syntax palettes" below) - color, never a header, is how a Bash
   block reads as Bash and a SQL block reads as SQL.
*/

/* ── Inline code ───────────────────────────────────────────────
   `text with `code` in it` - readable within a sentence, never
   competing with the surrounding prose. Fenced blocks (below) get
   their own distinct surface; this selector is deliberately undone
   for `pre code` further down so the two never fight over styling.
   Uses --color-text, not --code-text: since Issue 60, --code-text is
   the fenced block's light-on-dark foreground (see ../tokens/
   colors.css) - inline code stays on the ordinary light
   --color-surface-muted background, so it needs the ordinary dark
   text color instead, not the dark-surface one. */
code {
    font-family: var(--type-code-family);
    font-size: var(--type-code-size);
    color: var(--color-text);
    background: var(--color-surface-muted);
    padding: 0.15em 0.4em;
    border-radius: var(--radius-sm);
    word-break: break-word;
}

/* Fallback for a bare `<pre>` that isn't part of `.code-block` - only
   reachable via literal HTML typed into Markdown source rather than a
   fenced fence (the fence renderer always produces the wrapper
   below), kept so that edge case still reads as code, not an
   unstyled block. */
pre {
    background: var(--code-surface);
    border: 1px solid var(--code-border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    margin: var(--space-5) 0;
    overflow-x: auto;
}

pre code {
    background: none;
    padding: 0;
    border-radius: 0;
    line-height: var(--type-code-line-height);
}

/* ── Fenced code block ─────────────────────────────────────────
   Markup produced by apps.core.markdown's fence renderer:

     <div class="code-block">
       <button class="code-block__copy" data-code-copy>       (omitted if no language)
         <span class="visually-hidden">Copy code</span>
       </button>
       <pre class="code-block__pre" tabindex="0"><code class="language-python">...</code></pre>
     </div>

   No language header: the block is positioning context for the Copy
   button (below) and nothing else - there is deliberately no toolbar
   row to keep clean.
*/
.code-block {
    position: relative;
    margin: var(--space-5) 0;
    background: var(--code-surface);
    border: 1px solid var(--code-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
    overflow: hidden;
}

.code-block__pre {
    margin: 0;
    padding: var(--space-5) var(--space-4);
    overflow-x: auto;
    /* Preserve authored indentation and line breaks; never force-wrap
       a long line - horizontal scroll (below) is the intended behavior
       for both prose measure and shell-style output. */
    white-space: pre;
}

.code-block__pre code {
    /* Undo the inline-code treatment above - inside a fenced block,
       the surrounding <pre> already owns background/padding/radius. */
    background: none;
    color: var(--code-text);
    padding: 0;
    border-radius: 0;
    font-size: var(--type-code-size);
    line-height: var(--type-code-line-height);
    word-break: normal;
}

.code-block__pre ::selection {
    background: var(--code-selection);
}

.code-block__pre:focus-visible {
    /* --color-interactive (brand red) is tuned for 4.5:1 against
       white and falls well under 3:1 against --code-surface's dark
       grey (Issue 60) - --color-footer-link-hover is the same red
       already lightened for this exact dark-anchor surface family
       (see ../tokens/colors.css's "Footer" comment), reused here
       rather than deriving a second dark-surface red. */
    outline: 2px solid var(--color-footer-link-hover);
    outline-offset: -2px;
}

/* ── Copy button ────────────────────────────────────────────────
   A small icon-only button pinned to the block's top-right corner
   (position: relative on .code-block above), not a full-width
   toolbar - it floats above the code and stays put through the
   `.code-block__pre`'s own horizontal scroll, so it's always
   reachable, including on a narrow/mobile viewport mid-scroll. The
   copy/checkmark glyphs are CSS mask images (data URIs, defined
   inline here rather than as inline SVG markup) painted with
   `currentColor`, so no `<svg>` ever has to pass through
   apps.core.markdown's nh3 allowlist. */
.code-block__copy {
    --icon-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' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='9' width='13' height='13' rx='2'/%3E%3Cpath d='M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1'/%3E%3C/svg%3E");
    --icon-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.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");

    position: absolute;
    top: var(--space-3);
    right: var(--space-3);
    width: 2rem;
    height: 2rem;
    padding: 0;
    background: var(--code-surface);
    border: 1px solid var(--code-border);
    border-radius: var(--radius-sm);
    color: var(--code-muted);
    opacity: 0.8;
    cursor: pointer;
    transition: opacity var(--transition-fast), color var(--transition-fast),
        border-color var(--transition-fast), transform var(--transition-fast);
}

.code-block__copy::before {
    content: '';
    display: block;
    width: 100%;
    height: 100%;
    background-color: currentColor;
    -webkit-mask: var(--icon-copy) no-repeat center / 58%;
    mask: var(--icon-copy) no-repeat center / 58%;
}

.code-block__copy:hover {
    /* Same dark-surface red substitution as .code-block__pre:focus-
       visible above - --color-interactive fails contrast on this
       surface, --color-footer-link-hover is the vetted equivalent. */
    opacity: 1;
    color: var(--color-footer-link-hover);
    border-color: var(--color-footer-link-hover);
    transform: translateY(-1px);
}

.code-block__copy:focus-visible {
    opacity: 1;
    outline: 2px solid var(--color-footer-link-hover);
    outline-offset: 2px;
}

.code-block__copy[data-copy-state="copied"] {
    /* --status-success-text is tuned for a white surface (2.98:1
       here) - --code-function is this exact surface's own green,
       already at 7.37:1, reused rather than adding a dark-surface
       success token. --status-success-border stays as-is (11.4:1). */
    opacity: 1;
    color: var(--code-function);
    border-color: var(--status-success-border);
}

.code-block__copy[data-copy-state="copied"]::before {
    -webkit-mask-image: var(--icon-check);
    mask-image: var(--icon-check);
}

/* ── Syntax token colors ───────────────────────────────────────
   Pygments' own short class names (see apps.core.highlighting.TOKEN_CLASSES
   for the full allowlisted set) mapped to the semantic --code-* tokens
   in ../tokens/colors.css. Scoped under .code-block__pre so these
   single-letter classes can never collide with an unrelated class
   elsewhere on the page. Unmapped classes (whitespace, generic diff
   markers, etc.) simply inherit --code-text - color enhances
   structure here, it isn't the only source of meaning. */
.code-block__pre .k,
.code-block__pre .kc,
.code-block__pre .kd,
.code-block__pre .kn,
.code-block__pre .kp,
.code-block__pre .kr {
    color: var(--code-keyword);
    font-weight: 600;
}

.code-block__pre .s,
.code-block__pre .s1,
.code-block__pre .s2,
.code-block__pre .sa,
.code-block__pre .sb,
.code-block__pre .sc,
.code-block__pre .dl,
.code-block__pre .sd,
.code-block__pre .se,
.code-block__pre .sh,
.code-block__pre .si,
.code-block__pre .sx,
.code-block__pre .sr,
.code-block__pre .ss {
    color: var(--code-string);
}

.code-block__pre .m,
.code-block__pre .mb,
.code-block__pre .mf,
.code-block__pre .mh,
.code-block__pre .mi,
.code-block__pre .mo,
.code-block__pre .il {
    color: var(--code-number);
}

.code-block__pre .c,
.code-block__pre .c1,
.code-block__pre .ch,
.code-block__pre .cm,
.code-block__pre .cp,
.code-block__pre .cpf,
.code-block__pre .cs {
    color: var(--code-comment);
    font-style: italic;
}

.code-block__pre .nf,
.code-block__pre .fm,
.code-block__pre .nd {
    color: var(--code-function);
}

.code-block__pre .nc {
    color: var(--code-class);
}

.code-block__pre .nb,
.code-block__pre .bp,
.code-block__pre .kt {
    color: var(--code-builtin);
}

.code-block__pre .ne,
.code-block__pre .err {
    color: var(--code-error);
}

.code-block__pre .n,
.code-block__pre .nx,
.code-block__pre .na,
.code-block__pre .nl,
.code-block__pre .nn,
.code-block__pre .nt,
.code-block__pre .nv,
.code-block__pre .vc,
.code-block__pre .vg,
.code-block__pre .vi,
.code-block__pre .vm {
    color: var(--code-variable);
}

.code-block__pre .o,
.code-block__pre .ow {
    color: var(--code-operator);
}

.code-block__pre .p,
.code-block__pre .pm {
    color: var(--code-punctuation);
}

/* Literal.* (e.g. an unquoted YAML scalar value) reads like an
   implicit string. */
.code-block__pre .l {
    color: var(--code-string);
}

/* Generic.* - Pygments' MarkdownLexer's own token types for Markdown
   structure (headings, **bold**, *emphasis*), not "code" in the usual
   sense but one of the fenced languages this design system commits to
   supporting. */
.code-block__pre .gh,
.code-block__pre .gu {
    color: var(--code-class);
    font-weight: 600;
}

.code-block__pre .gs {
    font-weight: 600;
}

.code-block__pre .ge {
    font-style: italic;
}

/* ── Language-aware overrides ──────────────────────────────────
   The rules above are the *baseline*: used as-is by Python (and any
   language without a section below) - see "Language-family syntax
   palettes" further down for why Python's baseline reading "cooler
   blue/green" is a deliberate choice, not a placeholder. Prism/
   Pygments token classes don't carry identical meaning in every
   grammar (bash's `.nb` is a shell builtin; Python's `.nb` is
   `len`/`self`), so mapping every language onto the exact same class
   -> color table makes unrelated languages read as visually
   interchangeable. Each block below overrides a *few* specific
   classes, scoped to one language via the `code.language-*` ancestor
   selector - everything it doesn't mention still falls through to the
   shared baseline above, so this stays a set of small, targeted
   deviations, not a second full palette per language. This section
   only decides *which token role* a Pygments class plays per
   language (e.g. "bash's `.nn` is the --code-variable role"); the
   section below it decides what hue each role actually renders as
   per language family - two different, deliberately separate
   mechanisms. */

/* Bash / sh / shell / zsh / ksh - see
   apps.core.highlighting._DevOpsBashLexer for the five-tier tagging
   this styles. A privilege prefix (`sudo`, the shared `.kp` rule
   above) sits apart from: a native shell builtin (`cd`, `echo`, ... -
   Pygments' own `.nb`) and an external program being run (`apt`,
   `git`, `docker`, ... - re-tagged `.nn` so it can have its own
   color, distinct from a native builtin); one of that program's
   recognised subcommands (`update`, `clone`, ..., re-tagged
   `.nf`/Name.Function upstream, shares the plain --code-function role
   - a step below the command it belongs to, deliberately not bold,
   no override needed here); a `-x`/`--flag` option (shares
   --code-class); and a variable or `${...}` substitution (shares
   --code-number). Native builtins get their own richer, bolder role
   (--code-bash-command) rather than the shared --code-builtin -
   Python's `len`/`self` stay on the more subdued shared one,
   untouched. The privilege prefix and external-program roles both get
   a bash-specific *hue* too, not just a role - see "Language-family
   syntax palettes" below for the actual teal/green values; this
   section only says which role each is, not what color that role
   renders as here. */
.code-block__pre code.language-bash .nb,
.code-block__pre code.language-sh .nb,
.code-block__pre code.language-shell .nb,
.code-block__pre code.language-zsh .nb,
.code-block__pre code.language-ksh .nb {
    color: var(--code-bash-command);
    font-weight: 600;
}

.code-block__pre code.language-bash .nn,
.code-block__pre code.language-sh .nn,
.code-block__pre code.language-shell .nn,
.code-block__pre code.language-zsh .nn,
.code-block__pre code.language-ksh .nn {
    color: var(--code-variable);
    font-weight: 600;
}

.code-block__pre code.language-bash .na,
.code-block__pre code.language-sh .na,
.code-block__pre code.language-shell .na,
.code-block__pre code.language-zsh .na,
.code-block__pre code.language-ksh .na {
    color: var(--code-class);
}

.code-block__pre code.language-bash .nv,
.code-block__pre code.language-sh .nv,
.code-block__pre code.language-shell .nv,
.code-block__pre code.language-zsh .nv,
.code-block__pre code.language-ksh .nv,
.code-block__pre code.language-bash .si,
.code-block__pre code.language-sh .si,
.code-block__pre code.language-shell .si,
.code-block__pre code.language-zsh .si,
.code-block__pre code.language-ksh .si {
    color: var(--code-number);
}

/* JavaScript / TypeScript - see apps.core.highlighting._StudioJavascriptLexer
   for the builtin/function-call re-tagging this styles (TypeScript
   reuses Pygments' own TypescriptLexer as-is, untouched, but shares
   this same role mapping and the palette below it - a `.tsx`/`.ts`
   snippet's declarations, keywords and calls are structurally the
   same three things a `.js` snippet's are). A `.kd` declaration
   (`const`, `let`, `function`, `class`) reads as its own role,
   distinct from a `.k`/`.kn`/`.kp`/`.kr`/`.kc` control-flow keyword
   (`return`, `import`, `extends`, `true`) or a `.nf` function/method
   call (`greet(`, `console.log(`) - a plain identifier (a bare
   variable/property reference) is left unstyled-by-language, on the
   shared baseline. A recognised global (`console`, `Math`, `JSON`,
   ...) is `.nb`, already the shared --code-builtin teal - no override
   needed here. TypeScript's own `.kt` (a type annotation - `string`,
   `number`, ...) is deliberately left on that same shared
   --code-builtin teal too, rather than given a fourth role: a type
   annotation is closer to "this identifier is a kind of thing" than
   to a keyword, declaration, or call, so reusing the shared
   "recognised built-in vocabulary" role fits without inventing a
   dedicated one. */
.code-block__pre code.language-javascript .k,
.code-block__pre code.language-js .k,
.code-block__pre code.language-typescript .k,
.code-block__pre code.language-ts .k,
.code-block__pre code.language-javascript .kn,
.code-block__pre code.language-js .kn,
.code-block__pre code.language-typescript .kn,
.code-block__pre code.language-ts .kn,
.code-block__pre code.language-javascript .kp,
.code-block__pre code.language-js .kp,
.code-block__pre code.language-typescript .kp,
.code-block__pre code.language-ts .kp,
.code-block__pre code.language-javascript .kr,
.code-block__pre code.language-js .kr,
.code-block__pre code.language-typescript .kr,
.code-block__pre code.language-ts .kr,
.code-block__pre code.language-javascript .kc,
.code-block__pre code.language-js .kc,
.code-block__pre code.language-typescript .kc,
.code-block__pre code.language-ts .kc {
    color: var(--code-class);
}

.code-block__pre code.language-javascript .kd,
.code-block__pre code.language-js .kd,
.code-block__pre code.language-typescript .kd,
.code-block__pre code.language-ts .kd {
    color: var(--code-operator);
}

.code-block__pre code.language-javascript .nf,
.code-block__pre code.language-js .nf,
.code-block__pre code.language-typescript .nf,
.code-block__pre code.language-ts .nf {
    color: var(--code-variable);
}

/* JSON - keys (`.nt`) and string values (`.s2`) already fall on
   different shared baseline colors (sapphire / coral), and numbers
   (`.mi`) are already raspberry, so keys/values/numbers need no
   override here. Only `true`/`false`/`null` (`.kc`) need moving off
   the shared keyword lavender, so a boolean/null reads as its own
   "constant" identity rather than a stray keyword. */
.code-block__pre code.language-json .kc {
    color: var(--code-class);
}

/* HTML - attribute names (`.na`, shared baseline sapphire) and
   attribute values (a plain string, shared baseline coral) already
   read distinctly from each other; only a tag name (`.nt`) needs
   moving off the shared variable-group sapphire so a tag is
   immediately distinguishable from the attributes inside it. */
.code-block__pre code.language-html .nt {
    color: var(--code-class);
    font-weight: 600;
}

/* YAML / YML - a mapping key (`.nt`) and its value share the shared
   variable-group sapphire by default, which reads as one undifferentiated
   color down a whole document. Moving keys onto --code-class (violet)
   and leaving values on the shared sapphire gives every `key: value`
   line two distinct roles - the "violet/blue" pairing this language's
   palette below builds on - without needing a value-level override
   (plain scalars, quoted strings, and `${{ ... }}` substitutions
   already fall on their own shared roles). */
.code-block__pre code.language-yaml .nt,
.code-block__pre code.language-yml .nt {
    color: var(--code-class);
}

/* CSS - a class selector (`.nc`) and a tag selector (`.nt`) already
   read distinctly (violet vs. the shared sapphire, both via the
   baseline rules above - no override needed for either). A custom
   property or Sass variable (`--color-heading`, `$gap`, Pygments'
   `.nv`) is moved off that same shared sapphire onto --code-operator
   instead, so a property *reference* has its own identity apart from
   a plain selector/tag reference - reusing the existing magenta
   token rather than introducing a new one. */
.code-block__pre code.language-css .nv {
    color: var(--code-operator);
}

/* ── Language-family syntax palettes ─────────────────────────────
   The section above decides which *role* a Pygments class plays per
   language (e.g. "bash's `.nn` is the --code-variable role"). This
   section decides what *hue* a handful of those roles actually
   render as, per language family - a second, independent mechanism,
   layered on top rather than duplicating it.

   Mechanism: each block below re-declares the *value* of one or two
   of the existing --code-* custom properties, scoped to a
   `code.language-*` element instead of :root. Custom properties
   cascade normally, so a rule elsewhere in this file that reads
   `color: var(--code-keyword)` on a `.k` span still works completely
   unchanged - it just resolves to whatever value is closest up that
   span's own ancestor chain, which is now the language-scoped
   override instead of :root's default when the span sits inside one
   of these languages. No selector above this comment needed to
   change for this to work, and no new token names were added to
   ../tokens/colors.css - only a few of the *existing* ten are ever
   redeclared here, which is what keeps this restrained rather than a
   second full palette per language: 2-3 "identity" roles shift per
   family (the ones a reader's eye actually anchors on - keywords,
   declarations, function calls), while --code-string, --code-number,
   --code-comment, --code-punctuation and --code-error stay the same
   shared hue in every language, so strings and comments always read
   the same regardless of which language they're sitting in.

   Every value below was checked against --palette-dark-grey (the
   fenced-block --code-surface, Issue 60) for 4.5:1 (WCAG AA), the
   same bar every token in ../tokens/colors.css is held to - see that
   file's "Code: dark technical surface" comment.

   Python gets no block here: its baseline (keyword violet, function
   sage green, class amber, variable sapphire, builtin teal - all
   above) already reads as the restrained, muted family this issue
   asked for, so it doubles as both Python's palette and the shared
   fallback for any language below without its own block (plain text,
   JSON, unrecognised-but-Pygments-supported languages, ...). */

/* Bash / sh / shell / zsh / ksh - a privilege prefix (`sudo`, `.kp`)
   and the external program being invoked (`apt`, `git`, `docker`,
   `.nn`) are the two words a reader's eye goes to first in a DevOps
   snippet, so those are the two roles retuned toward teal/green for
   "slightly more terminal-like". The native-builtin role
   (--code-bash-command) is already its own dedicated teal and the
   subcommand role already falls on --code-function's green
   unscoped (see the role-mapping comment above) - between those two
   and this override, four of bash's five roles land in the
   teal/green family; only the flag/option role (amber,
   --code-class) and the variable-substitution role (rose,
   --code-number) stay on their shared hues, as small supporting
   accents rather than a fully green block. */
.code-block__pre code.language-bash,
.code-block__pre code.language-sh,
.code-block__pre code.language-shell,
.code-block__pre code.language-zsh,
.code-block__pre code.language-ksh {
    --code-keyword: #87C9B9;
    --code-variable: #8BC0D0;
}

/* JavaScript / TypeScript - warmer than every other family on
   purpose: control-flow keywords (--code-class role) move to muted
   amber-orange, declarations (--code-operator role) to muted
   rose-pink, and function calls/plain identifiers (--code-variable
   role) to a muted gold - a yellow-orange-pink neighborhood, distinct
   from Python's cooler violet/blue/green and Bash's teal/green. */
.code-block__pre code.language-javascript,
.code-block__pre code.language-js,
.code-block__pre code.language-typescript,
.code-block__pre code.language-ts {
    --code-class: #D5AE90;
    --code-operator: #D49BB2;
    --code-variable: #D7C18E;
}

/* SQL - keywords (`SELECT`, `FROM`, `WHERE`, `JOIN`, ...) move off
   the shared violet onto a cyan-teal; table/column identifiers
   already fall on the shared sapphire blue (--code-variable,
   unscoped, no override needed) - together, "keyword cyan, identifier
   blue" is the "blue/cyan" pairing this language asked for, from a
   single override. */
.code-block__pre code.language-sql {
    --code-keyword: #87C4C9;
}
