/* src/styles/case-figures.css */
/* Case-study gallery — the `/proekti/:slug` body outlet.
 *
 * Ships as a code asset, not editor CSS: body content is markdown-rendered
 * at publish time, so its elements are not page-tree nodes and editor class
 * rules for them would not survive the publish tree-shake. Interactive state
 * (video pointer-events, the compare handle and grip) is set inline from
 * motion.js — only static base styles live here.
 */

.case-figures p {
  margin: 0;
}

.case-figures img,
.case-figures video {
  display: block;
  width: 100%;
  /* Gallery media is presentation, not content to drag or select. Videos
   * keep pointer events here — JS sets pointer-events: none inline only when
   * it strips the controls, so the no-JS / reduced-motion state stays usable. */
  user-select: none;
  -webkit-user-drag: none;
}

.case-figures iframe {
  display: block;
  width: 100%;
  /* Vimeo/YouTube embeds arrive as raw width="640" height="360" attributes
   * from the source markdown — without this the iframe renders at that fixed
   * size instead of filling the column like every other gallery item, which
   * reads as a blank gap around it. aspect-ratio + height:auto lets a
   * replaced element scale responsively off its authored 16:9 dimensions. */
  aspect-ratio: 16 / 9;
  height: auto;
  border: 0;
}

.img-compare:focus-visible {
  outline: 2px solid var(--color-brand);
  outline-offset: -2px;
}


/* src/styles/page-fade.css */
/* Embrand Studio — page fade overlay.
 *
 * One fixed white sheet, drawn as html::after so it exists at first paint,
 * before <body> has even been parsed. src/scripts/page-fade.js drives it
 * through three states on <html>:
 *
 *   hold    opaque, no animation — from head parse until there is something
 *           to reveal. Without this the fade clock starts when the script
 *           parses, so the sheet is gone before the page has painted and
 *           content appears to land on top of it.
 *   enter   opaque -> transparent   (arriving on a page)
 *   exit    transparent -> opaque   (leaving through an internal link)
 *
 * --page-fade-enter is written inline by the script: 500ms on a cold load,
 * 125ms when the visitor arrived from an internal link. The value below is
 * the fallback if the script never gets to run.
 */

:root {
  --page-fade-enter: 500ms;
  --page-fade-exit: 125ms;
}

html::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 2147483647;
  background: #fff;
  opacity: 0;
  pointer-events: none;
}

/* Holding and closing both swallow pointer events, so nothing behind the
 * sheet can be clicked while it is covering the page. */
html[data-page-fade='hold']::after {
  opacity: 1;
  pointer-events: auto;
}

html[data-page-fade='enter']::after {
  animation: eb-page-fade-enter var(--page-fade-enter) ease forwards;
}

html[data-page-fade='exit']::after {
  animation: eb-page-fade-exit var(--page-fade-exit) ease forwards;
  pointer-events: auto;
}

@keyframes eb-page-fade-enter {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes eb-page-fade-exit {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* The script bails out entirely under reduced motion; this is belt and
 * braces so a stale attribute can never leave a sheet on screen. */
@media (prefers-reduced-motion: reduce) {
  html::after {
    display: none;
  }
}


/* src/styles/rich-body.css */
/* Rich-text body content — the markdown-rendered `<instatic-outlet>` regions.
 *
 * Ships as a code asset, not editor CSS, for the same reason `case-figures.css`
 * does: the elements inside a rendered outlet (`<p>`, `<a>`, `<ul>`) are produced
 * by the markdown renderer at publish time, so they are not page-tree nodes and
 * editor class rules that name them would not survive the publish tree-shake
 * (CLAUDE.md §3.1, "Only classes on real nodes survive publish").
 *
 * Consumers:
 *   - `.term-page__body`     — the `branding-termini` post-type template
 *   - `.faq-answer`          — /chesti-vaprosi accordion answers
 *
 * `.glossary-term__body` was a consumer until 2026-09-06, when the
 * /branding-termini index was trimmed from full markdown-rendered bodies to
 * a plain-text `{currentEntry.term}` teaser (`.glossary-term__teaser`) — no
 * outlet, no markdown, no links, so nothing here applies to the index any more.
 *
 * The global reset ships `:where(a) { color: inherit; text-decoration: inherit }`,
 * so an inline link inside body copy is indistinguishable from plain text until
 * it is styled here.
 *
 * 2026-09-06 — tried Lilex italic on the LINKS. Reverted same day: client
 * wanted the italic on the definition prose itself instead, links back to
 * plain Karst SemiBold. Current shape: `.term-page__body p` carries the
 * italic Lilex voice, `.term-page__body a` / `.faq-answer a` explicitly reset
 * back to upright Karst — the reset matters because font-style/font-family
 * are inherited, so without it a link would inherit the paragraph's italic
 * Lilex instead of standing apart from it. The two together read as: flowing
 * italic definition text, with upright bold black anchors breaking through it.
 *
 * 2026-09-06 (later same day) — definition text size, `.term-page__body`
 * only (not `.faq-answer`): first dropped two rungs off the body-copy ladder
 * (body-lg 26 → body 24, the wrapper's own `.text-body` utility → body-sm 17
 * → caption 14), then brought back up one rung to `--text-body-sm-*` (17px /
 * 24px line-height) — the caption tier read too small for running prose.
 * Set explicitly on both the paragraph and the link rule rather than relying
 * on the link inheriting the paragraph's size: the two rules already diverge
 * in font-family (Lilex vs Karst), and Karst/Lilex don't share the same
 * x-height at a given px value, so leaving the link's size to inherit would
 * make "same number" not read as "same size" — stating it on both keeps them
 * visually matched, not just numerically matched.
 *
 * Sizing edits here MUST go through `site_write_code_asset` on this file, not
 * `site_apply_css` — the latter writes to a separate editor-CSS layer and
 * silently produces a second, duplicate ambient rule for the same selector
 * instead of updating this one (caught and reverted 2026-09-06: two stray
 * `.term-page__body p` / `.term-page__body a` rules briefly existed in the
 * editor CSS store alongside these, at a different size).
 *
 * 🔴 2026-09-08 — `site_write_code_asset` REPORTS FAILURE ON A SUCCESSFUL
 * WRITE. Every call to it (and to `site_list_code_assets` /
 * `site_read_code_asset`) returns `Cannot read properties of undefined
 * (reading 'digest')` while the Site editor is connected and healthy — but the
 * write itself lands. A one-line `/* probe *\/` sent to test whether the tool
 * was usable at all silently replaced this entire file, and the 4,318-char
 * original had to be restored from a copy read out of the store. There is no
 * `expectedHash` available to make `site_patch_code_asset` usable either, since
 * the two read tools throw the same error. **Treat the error as advisory, verify
 * off disk, and never send a throwaway payload to a live code asset:**
 *
 *   sqlite3 instatic/.tmp/dev.db \
 *     "select settings_json from site where id='default';" \
 *     | python3 -c "import json,sys; [print(f['path'], len(f['content'])) \
 *         for f in json.load(sys.stdin)['site']['files']]"
 *
 * One property on the link rule is a correction of something inherited, not a
 * free choice:
 *
 *   font-feature-settings: 'ss03' 1
 *     Karst's `.ss03` utility ships fine and is used widely on real nodes, but
 *     a markdown-rendered `<a>` cannot carry a class, so the feature has to be
 *     set as a property here rather than borrowed from the utility.
 */

.term-page__body p {
  font-family: var(--font-mono);
  font-style: italic;
  font-size: var(--text-body-sm-size);
  line-height: var(--text-body-sm-line-height);
}

.term-page__body a,
.faq-answer a {
  font-family: var(--font-body);
  font-weight: var(--font-weight-semibold);
  font-style: normal;
  font-feature-settings: 'ss03' 1;
  color: var(--black-d-4);
  text-decoration-line: none;
}

.term-page__body a {
  font-size: var(--text-body-sm-size);
  line-height: var(--text-body-sm-line-height);
}

/* Multi-paragraph bodies: the global reset zeroes every margin, so paragraphs
 * after the first need their own rhythm restored. */
.term-page__body p + p,
.faq-answer p + p {
  margin-top: var(--spacing-base);
}

.term-page__body ul,
.term-page__body ol,
.faq-answer ul,
.faq-answer ol {
  margin-top: var(--spacing-base);
  padding-left: var(--spacing-lg);
}

.term-page__body li,
.faq-answer li {
  margin-top: var(--spacing-xs);
}

/* 2026-09-08 — list rendering, finished. Found via `/privacy`, the first page
 * on the site to put a list inside body prose: measured across all 31
 * published `branding-termini` term pages and all 17 `/chesti-vaprosi`
 * answers, not one body contains a `<li>`, so the four list rules above had
 * shipped since this file was written without ever rendering. Two gaps were
 * invisible for exactly that reason.
 *
 *   list-style-type
 *     The global reset ships `:where(ol, ul, menu) { list-style: none }`, and
 *     nothing here put it back — so items rendered as indented blocks with
 *     4.3px between them, unreadable as a list wherever item boundaries carry
 *     the meaning. Zero specificity, so naming the property at all is enough.
 *     Marker colour left inherited on purpose: a coloured marker is decoration
 *     this design system does not use anywhere else.
 *
 *   the type ramp, `.term-page__body` only
 *     `li` was never given the voice its own `p` carries, so items inherited
 *     the wrapper's `.text-body` utility and came out 24px/36 upright Karst
 *     between 17px/24 italic Lilex paragraphs — louder than the prose they sit
 *     inside, hierarchy inverted. Scoped to `.term-page__body` for the same
 *     reason the size rules above are: `.faq-answer`'s wrapper already carries
 *     `.text-body-sm-emphasis`, which IS Lilex italic at `--text-body-sm-*`,
 *     so its items inherit the right voice and restating it here would be
 *     duplicating a value that is already correct.
 *
 * `/privacy` does not consume any of this — it was built on its own
 * `.legal-doc__*` classes by client direction (match the Glossary's
 * typography, don't share its classes; build-log 2026-09-08). This fix is so
 * the next glossary definition or FAQ answer that needs a list gets one that
 * reads correctly, rather than reproducing the bug `/privacy` surfaced.
 */
.term-page__body li {
  font-family: var(--font-mono);
  font-style: italic;
  font-size: var(--text-body-sm-size);
  line-height: var(--text-body-sm-line-height);
}

.term-page__body ul,
.faq-answer ul {
  list-style-type: disc;
}

.term-page__body ol,
.faq-answer ol {
  list-style-type: decimal;
}
