/* * shadcn/typeset * https://ui.shadcn.com/docs/typeset. */ @layer components { .typeset { --typeset-font-body: inherit; --typeset-font-heading: var(--font-heading); --typeset-font-mono: var(--font-mono); --typeset-size: 1em; --typeset-leading: 1.75; --typeset-flow: 1.25em; } } @layer components { .typeset { font-family: var(--typeset-font-body); font-size: calc(var(--typeset-size) * 1.125); line-height: var(--typeset-leading); color: var(--color-foreground, currentColor); overflow-wrap: break-word; margin-trim: block-start; @media (min-width: 48rem), print { font-size: var(--typeset-size); } --typeset-muted: var( --color-muted-foreground, color-mix(in oklab, currentColor 60%, transparent) ); --typeset-rule: var( --color-border, color-mix(in oklab, currentColor 20%, transparent) ); } .typeset *:not( :where( .not-typeset, [data-not-typeset], .not-typeset *, [data-not-typeset] * ) ) { /* Paragraphs. */ &:where(p) { margin-block-start: var(--typeset-flow); margin-block-end: 0; } /* Headings. */ &:where(h1, h2, h3, h4, h5, h6) { color: var(--color-foreground, currentColor); font-family: var(--typeset-font-heading); font-weight: 600; margin-block-end: 0; } &:where(h1) { font-size: 1.75em; line-height: 1.3; margin-block-start: var(--typeset-flow); } &:where(h2) { font-size: 1.25em; line-height: 1.4; margin-block-start: calc(var(--typeset-flow) * 1.4); } &:where(h3) { font-size: 1.125em; line-height: 1.45; margin-block-start: var(--typeset-flow); } &:where(h4) { font-size: 1em; line-height: 1.5; margin-block-start: var(--typeset-flow); } &:where(h5) { font-size: 0.875em; line-height: 1.5; font-weight: 500; color: var(--typeset-muted); margin-block-start: calc(var(--typeset-flow) / 0.875); } &:where(h6) { font-size: 0.8125em; line-height: 1.5; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--typeset-muted); margin-block-start: calc(var(--typeset-flow) / 0.8125); } /* Anchors. */ &:where([id]) { scroll-margin-block-start: var(--typeset-flow); } /* Headings own the space below them. */ &:where(h1 + *, h2 + *, h3 + *, h4 + *, h5 + *, h6 + *) { margin-block-start: 1em; } &:where(:is(h1, h2, h3, h4) :is(code)) { font-size: 0.9em; } /* Links. */ &:where(a) { color: inherit; font-weight: 500; text-decoration-line: underline; text-decoration-color: color-mix(in oklab, currentColor 30%, transparent); } &:where(a:hover) { text-decoration-color: currentColor; } &:where(a:focus-visible) { outline: 2px solid var(--color-ring, currentColor); outline-offset: 2px; border-radius: 0.125em; } &:where(:is(h1, h2, h3, h4, h5, h6) :is(a)) { font-weight: inherit; } /* Inline semantics. */ &:where(strong, b) { font-weight: 600; } &:where(:is(h1, h2, h3, h4) :is(strong, b)) { font-weight: 600; } &:where(mark) { background-color: color-mix( in oklab, oklch(0.86 0.17 95) 40%, transparent ); color: inherit; padding: 0.05em 0.15em; border-radius: 0.2em; } &:where(abbr[title]) { text-decoration-line: underline; text-decoration-style: dotted; text-underline-offset: 0.2em; cursor: help; } &:where(del, s) { color: var(--typeset-muted); text-decoration-line: line-through; } &:where(sup, sub) { font-size: 0.75em; line-height: 0; position: relative; vertical-align: baseline; } &:where(sup) { top: -0.5em; } &:where(sub) { bottom: -0.25em; } &:where(sup a) { text-decoration-line: none; font-weight: 500; } /* Lists. */ &:where(ul) { list-style-type: disc; } &:where(ol) { list-style-type: decimal; } &:where(ul ul) { list-style-type: circle; } &:where(ul ul ul) { list-style-type: square; } &:where(ol[type="a" i]) { list-style-type: lower-alpha; } &:where(ol[type="i" i]) { list-style-type: lower-roman; } &:where(ol[type="A" s]) { list-style-type: upper-alpha; } &:where(ol[type="I" s]) { list-style-type: upper-roman; } &:where(ul, ol) { margin-block-start: var(--typeset-flow); margin-block-end: 0; padding-inline-start: 1.5em; } &:where(li) { margin-block-start: 0.5em; padding-inline-start: 0.4em; } &:where(li > p, li > ul, li > ol) { margin-block-start: 0.5em; } &:where(ul > li)::marker { color: var(--typeset-muted); } &:where(ol > li)::marker { color: var(--typeset-muted); } /* GFM task lists. */ &:where(ul.contains-task-list) { list-style-type: none; padding-inline-start: 0.25em; } &:where(li.task-list-item > input[type="checkbox"]) { margin-inline-end: 0.5em; vertical-align: -0.1em; accent-color: var(--color-primary, currentColor); } /* Disclosures. */ &:where(details) { margin-block-start: var(--typeset-flow); margin-block-end: 0; } &:where(summary) { cursor: pointer; font-weight: 500; } &:where(summary)::marker { color: var(--typeset-muted); } /* Keyboard keys. */ &:where(kbd) { font-family: inherit; font-size: 0.85em; font-weight: 500; border: 1px solid var(--typeset-rule); border-block-end-width: 2px; border-radius: min(calc(var(--radius, 0.5em) * 0.6), 0.35em); padding: 0.0625em 0.35em; } /* Definition lists. */ &:where(dl) { margin-block-start: var(--typeset-flow); margin-block-end: 0; } &:where(dt) { font-weight: 500; margin-block-start: 1em; } &:where(dt + dt) { margin-block-start: 0.25em; } &:where(dd) { margin-block-start: 0.25em; margin-inline-start: 0; padding-inline-start: 1em; color: var(--typeset-muted); } /* Inline code. */ &:where(:not(pre) > code) { background-color: var( --color-muted, color-mix(in oklab, currentColor 8%, transparent) ); font-family: var(--typeset-font-mono); font-size: 0.85em; border-radius: min(calc(var(--radius, 0.5em) * 0.6), 0.35em); padding: 0.125em 0.3em; } /* Code blocks. */ &:where(pre) { background-color: var( --color-muted, color-mix(in oklab, currentColor 8%, transparent) ); font-family: var(--typeset-font-mono); font-size: 0.875em; line-height: 1.5; tab-size: 2; direction: ltr; border-radius: var(--radius, 0.5em); padding: 0.75em 1em; overflow-x: auto; margin-block-start: calc(var(--typeset-flow) / 0.875); margin-block-end: 0; } &:where(pre code) { background-color: transparent; font-family: inherit; font-size: inherit; padding: 0; border-radius: 0; } /* Blockquote. */ &:where(blockquote) { border-inline-start: 2px solid var(--typeset-rule); padding-inline-start: 1em; margin-block-start: var(--typeset-flow); margin-block-end: 0; margin-inline: 0; } /* Dividers. */ &:where(hr) { border: 0; border-block-start: 1px solid var(--typeset-rule); margin-block-start: calc(var(--typeset-flow) * 2.4); margin-block-end: 0; } &:where(hr + h1, hr + h2, hr + h3, hr + h4) { margin-block-start: var(--typeset-flow); } /* GFM footnotes. */ &:where(.footnotes, [data-footnotes]) { margin-block-start: calc(var(--typeset-flow) * 2); border-block-start: 1px solid var(--typeset-rule); padding-block-start: var(--typeset-flow); font-size: 0.875em; color: var(--typeset-muted); } /* Math. */ &:where(math[display="block"]) { margin-block-start: var(--typeset-flow); margin-block-end: 0; overflow-x: auto; overflow-y: hidden; padding-block: 0.25em; } /* Media. */ &:where(img, video) { border-radius: var(--radius, 0.5em); max-width: 100%; height: auto; margin-block-start: var(--typeset-flow); margin-block-end: 0; } &:where(p img) { margin-block-start: 0; } &:where(figure) { margin-block-start: var(--typeset-flow); margin-block-end: 0; margin-inline: 0; } &:where(figcaption, caption) { color: var(--typeset-muted); font-size: 0.875em; text-align: center; margin-block-start: calc(0.75em / 0.875); } &:where(caption) { caption-side: bottom; } /* Tables. Separators sit on cells, not tr:last-child: append-safe. Bare tables stay real tables (keep their semantics) and wrap to fit. */ &:where(table) { max-width: 100%; font-size: 1em; line-height: 1.5; font-variant-numeric: tabular-nums; border-collapse: separate; border-spacing: 0; border-block-end: 1px solid var(--typeset-rule); margin-block-start: var(--typeset-flow); margin-block-end: 0; } /* Horizontal scroll for any wide block. Wrap it and the wrapper owns the flow margin. Tables shrink to fit, so widen the table to make it scroll instead of compress. */ &:where(.typeset-scroll) { overflow-x: auto; margin-block-start: var(--typeset-flow); } &:where(.typeset-scroll > *) { margin-block-start: 0; } &:where(.typeset-scroll table) { width: max-content; max-width: none; } &:where(thead th) { font-weight: 500; text-align: start; white-space: nowrap; padding: 0.65em 1em; } &:where(:is(tbody, tfoot) :is(td, th)) { padding: 0.75em 1em; text-align: start; vertical-align: top; border-block-start: 1px solid var(--typeset-rule); } &:where(tbody th, tfoot th) { font-weight: 500; } &:where(th:first-child, td:first-child) { padding-inline-start: 0; } &:where(th[align="center"], td[align="center"]) { text-align: center; } &:where(th[align="right"], td[align="right"]) { text-align: end; } /* Blocks inside list items keep the list's tighter rhythm. */ &:where(li > blockquote, li > table, li > figure) { margin-block-start: 0.5em; } &:where(li > pre) { margin-block-start: calc(0.5em / 0.875); } @media print { &:where(pre, table, blockquote, figure) { break-inside: avoid; } &:where(h1, h2, h3, h4) { break-after: avoid; } } /* Forced colors strips the code background, so give it a border. */ @media (forced-colors: active) { &:where(:not(pre) > code) { border: 1px solid; } } } /* First child adds no space above. Last so it wins ties. */ .typeset > :where(:first-child):not( :where( .not-typeset, [data-not-typeset], .not-typeset *, [data-not-typeset] * ) ), .typeset > :where(:first-child) > :where(:first-child):not( :where( .not-typeset, [data-not-typeset], .not-typeset *, [data-not-typeset] * ) ), .typeset :where( li > :first-child, blockquote > :first-child, td > :first-child, th > :first-child, dd > :first-child, figure > :first-child, figure > picture > img ):not( :where( .not-typeset, [data-not-typeset], .not-typeset *, [data-not-typeset] * ) ) { margin-block-start: 0; } }