Files
hyperframes/docs/custom.css
T
Ular Kimsanov 9652a6324a docs: Studio app light palette, plus movable film rows and stacked remix shelves on Inspiration (#6414)
* docs: light mode in the studio app's palette

Light mode takes the Studio app light palette (packages/desktop index.css)
instead of the hyperframes.dev beige ground: paper, cards, ink levels and
the light accent ink for links. Plain code text uses the page ink.
Dark mode (Night) is unchanged.

* docs(examples): film rows move by hand and remix shelves stack

The Inspiration film rows drift by a script, as on the homepage
(HyperFramesShowcase): drag, a sideways swipe or shift+wheel moves a row,
and keyboard focus centres a card. Remix shelves are columns that each
stack their cards, so cards of different shapes leave no holes.
2026-10-26 12:17:32 +00:00

1828 lines
49 KiB
CSS

/* HyperFrames Design System — Mintlify Theme Overrides */
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap");
@font-face {
font-family: "TT Norms Pro";
src: url("https://www-static-assets.heygen.com/fonts/tt-norms/TT_Norms_Pro_Light.woff2")
format("woff2");
font-weight: 300;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "TT Norms Pro";
src: url("https://www-static-assets.heygen.com/fonts/tt-norms/TT_Norms_Pro_Normal.woff2")
format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "TT Norms Pro";
src: url("https://www-static-assets.heygen.com/fonts/tt-norms/TT_Norms_Pro_Medium.woff2")
format("woff2");
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "TT Norms Pro";
src: url("https://www-static-assets.heygen.com/fonts/tt-norms/TT_Norms_Pro_DemiBold.woff2")
format("woff2");
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "TT Norms Pro";
src: url("https://www-static-assets.heygen.com/fonts/tt-norms/TT_Norms_Pro_Bold.woff2")
format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
/* ── Light mode (default) ── */
/*
* NOTE: All custom variables are namespaced with `--hf-` to avoid
* colliding with Mintlify's Tailwind color system, which owns names
* like `--background-light` / `--background-dark` and uses them via
* `rgb(var(--background-light)/<alpha>)`. Overriding those with hex
* values breaks the rgb() call and makes surfaces transparent (e.g.
* the "Copy page" dropdown panel in light mode).
*/
/* Light mode is the Studio app's light palette (packages/desktop/src/index.css :root,
* "Graphite"): warm paper, near-white cards and ink on hue 70. */
:root {
--hf-background: #f2f0ed;
--hf-background-light: oklch(0.987 0.005 70);
--hf-surface2: oklch(1 0 70);
--hf-border-color: oklch(0.205 0.003 70 / 0.08);
--hf-border-color-light: oklch(0.205 0.003 70 / 0.15);
--hf-text: oklch(0.205 0.003 70);
--hf-text-secondary: oklch(0.403 0.003 70);
--hf-text-tertiary: oklch(0.503 0.003 70);
--hf-heading: oklch(0.205 0.003 70);
--hf-code-bg: oklch(0.987 0.005 70);
--hf-ui-border: oklch(0.205 0.003 70 / 0.08);
--hf-sidebar-rail: oklch(0.205 0.003 70 / 0.15);
--hf-sidebar-text: oklch(0.403 0.003 70);
--hf-floating-input-shadow: 0 1px 2px oklch(0.2 0.01 70 / 0.06), 0 10px 30px oklch(0.2 0.01 70 / 0.06);
--mintlify-slot-header-height: 3rem;
/* The mint accent is for dark grounds; on paper links take the app's light accent ink. */
--hf-brand: oklch(0.45 0.096 164);
--hf-brand-soft: color-mix(in oklch, oklch(0.536 0.114 164) 13%, transparent);
--hf-video-accent: #3ce6ac;
--hf-glass: rgb(242 240 237 / 0.82);
--hf-chip: oklch(1 0 70);
--hf-accent-green: #1a7a0a;
--hf-accent-green-light: rgba(26, 122, 10, 0.07);
--hf-accent-green-border: rgba(26, 122, 10, 0.25);
--hf-accent-blue: #2563eb;
--hf-accent-blue-light: rgba(37, 99, 235, 0.06);
--hf-accent-blue-border: rgba(37, 99, 235, 0.2);
--hf-accent-purple: #7c3aed;
--hf-accent-purple-light: rgba(124, 58, 237, 0.06);
--hf-accent-purple-border: rgba(124, 58, 237, 0.2);
--hf-selection-bg: rgba(128, 128, 128, 0.2);
}
/* ── Dark mode ── */
/* Dark mode is the Studio app's Night palette (packages/desktop/src/index.css,
* :root[data-chrome="night"]): warm paper, cards and ink on hue 70. */
.dark,
[data-theme="dark"] {
--hf-background: #201e1c;
--hf-background-light: #272522;
--hf-surface2: #2f2c29;
--hf-border-color: rgb(245 243 241 / 0.1);
--hf-border-color-light: rgb(245 243 241 / 0.16);
--hf-text: #e2e0de;
--hf-text-secondary: #b8b6b4;
--hf-text-tertiary: #979593;
--hf-heading: #f5f3f1;
--hf-code-bg: #24211e;
--hf-ui-border: rgb(245 243 241 / 0.075);
--hf-sidebar-rail: rgb(245 243 241 / 0.1);
--hf-sidebar-text: #b8b6b4;
--hf-floating-input-shadow: 0 8px 28px rgba(0, 0, 0, 0.4), 0 1px 4px rgba(0, 0, 0, 0.4);
--hf-brand: #3ce6ac;
--hf-brand-soft: rgba(60, 230, 172, 0.12);
--hf-glass: rgb(32 30 28 / 0.72);
--hf-chip: rgb(255 255 255 / 0.08);
--hf-accent-green: #22c55e;
--hf-accent-green-light: rgba(34, 197, 94, 0.1);
--hf-accent-green-border: rgba(34, 197, 94, 0.3);
--hf-accent-blue: #3b82f6;
--hf-accent-blue-light: rgba(59, 130, 246, 0.1);
--hf-accent-blue-border: rgba(59, 130, 246, 0.3);
--hf-accent-purple: #a78bfa;
--hf-accent-purple-light: rgba(167, 139, 250, 0.1);
--hf-accent-purple-border: rgba(167, 139, 250, 0.3);
--hf-selection-bg: rgba(255, 255, 255, 0.15);
}
/* ── Typography ── */
body {
font-family:
"TT Norms Pro",
"Inter",
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
sans-serif;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family:
"TT Norms Pro",
"Inter",
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
sans-serif;
}
h1,
h2 {
letter-spacing: -0.02em;
}
h3 {
letter-spacing: -0.01em;
}
/* ── Workflow routing ── */
.hf-workflow-routes {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1.75rem 1.25rem;
margin: 1.5rem 0;
}
.hf-workflow-route {
display: flex;
flex-direction: column;
gap: 0.6rem;
color: inherit;
text-decoration: none;
border-bottom: 0 !important;
box-shadow: none !important;
}
.hf-workflow-route:hover .hf-workflow-route-title {
color: var(--hf-accent-green);
}
.hf-workflow-route video {
display: block;
width: 100%;
aspect-ratio: 16 / 9;
margin: 0;
border-radius: 0.5rem;
background: #000;
object-fit: cover;
pointer-events: none;
}
/* A route with no preview clip: same box, no black rectangle. */
.hf-workflow-route-noclip {
display: block;
width: 100%;
aspect-ratio: 16 / 9;
margin: 0;
border-radius: 0.5rem;
background: color-mix(in srgb, currentColor 8%, transparent);
}
.hf-workflow-route-title {
display: block;
color: var(--hf-heading);
font-weight: 650;
line-height: 1.35;
transition: color 120ms ease;
}
.hf-workflow-route-copy {
display: block;
margin-top: 0.3rem;
color: var(--hf-text-secondary);
font-size: 0.9rem;
line-height: 1.5;
}
@media (max-width: 639px) {
.hf-workflow-routes {
grid-template-columns: 1fr;
}
}
/* Code font — IBM Plex Mono (loaded via Google Fonts above).
*
* Deliberately scoped to real code elements. The previous rule also matched
* [class*="code"] / [class*="Code"], which caught any element whose class
* merely contained that substring — including every Accordion, whose wrapper
* carries the Tailwind utility `dark:bg-codeblock`. That set the whole
* accordion (and, by inheritance, its title and prose) in monospace, so plain
* sentences rendered like terminal output. Syntax tokens inside `pre` inherit
* from `pre`, so they do not need a selector of their own. */
code,
pre,
pre code,
kbd,
samp {
font-family: "IBM Plex Mono", "SF Mono", "Fira Code", monospace;
}
/* ── Code block copy button ── */
/*
* One button, every code block on the site, and all of it is Tailwind
* utilities on the element itself. The shipped bundle has no `--copy-*`
* custom property, no documented class and no docs.json key for it (its only
* button tokens, `--button-*`, belong to the <Button> component, which this
* is not), so there is no supported hook to prefer. `custom.css` is the
* documented extension point; `[data-testid]` is the handle, because a
* testid outlives the utility soup wrapped around it.
*
* What was wrong: the resting icon is `text-gray-400 / dark:text-white/40`,
* which measures 2.37:1 on a catalog page and 2.57:1 on a plain one against
* the surface behind it. Both are under the 3:1 that 1.4.11 asks of a
* control. Dark mode was the better half of the pair at 3.8:1, over the line
* but not by enough to see. It sat in a 26px box and did not change on
* hover, so a reader could not read it, could not comfortably hit it, and
* was never told it was a control.
*
* What is deliberately left alone: the copied state. Mintlify already swaps
* the clipboard for a check in the brand colour and fills a sibling
* `role="status"` with "Copied" — the announcement pattern — so the rules
* below exclude `.text-primary` instead of restyling it.
*
* Nothing here moves. The plate and the icon change colour over 100ms; there
* is no transform and no keyframe, the same rule the explorer above follows.
*/
.code-block [data-testid="copy-code-button"] {
position: relative;
/* 44x44 of pointer and touch target, given back to the layout by the same
9px it took, so every header keeps its height and the floating variant
keeps its top-3 right-4 anchor. */
width: 44px;
height: 44px;
margin: -9px;
/* The plate is ::before, so the 44px box itself is never painted — the
conditional `bg-gray-100` Mintlify puts on the floating variant would
otherwise render as a 44px slab. */
background-color: transparent;
}
/* The plate: 26px, the size the button used to be. ::before precedes the
<svg> in the box tree, so it paints under the icon without a z-index. */
.code-block [data-testid="copy-code-button"]::before {
content: "";
position: absolute;
inset: 9px;
border-radius: 6px;
background-color: transparent;
transition: background-color 100ms ease;
}
.code-block [data-testid="copy-code-button"]:hover::before {
background-color: color-mix(in srgb, var(--hf-text) 10%, transparent);
}
/* `:not(.text-primary)` is the resting icon only; the check keeps Mintlify's
own colour. Two classes and an attribute because `dark:text-white/40` is
`.dark .text-white\/40`, and a shorter selector silently loses to it. */
.code-block [data-testid="copy-code-button"] svg:not(.text-primary) {
color: var(--hf-text-secondary);
transition: color 100ms ease;
}
.code-block [data-testid="copy-code-button"]:hover svg:not(.text-primary) {
color: var(--hf-text);
}
/* The ring sits on the element that has focus, not on the plate, and is
pulled inside the 44px target so it reads as a ring around the icon
rather than a box floating clear of it. */
.code-block [data-testid="copy-code-button"]:focus-visible {
border-radius: 14px;
outline: 2px solid var(--hf-brand);
outline-offset: -6px;
}
/* ── Install command copy button ── */
/*
* The command itself is a bare <code>, so it inherits the chrome Mintlify puts
* on every inline code span: a translucent plate and a 6px radius. Inside this
* control that plate is a second rounded rectangle in a slightly different
* tone, and its two right-hand corners let the row's own background through —
* which reads as a gap between the field and the button. The layout was never
* gapped; the elements are flush (no flex gap, no margin). Drop the inherited
* plate and the field and the button become one surface, divided by the
* field's 1px border-right and nothing else. That divider lives on the field
* rather than on the button because the focus ring rounds the button to 14px,
* which would bend a border on that edge out of sight while it is focused.
*/
.hf-install-command code {
background: none;
border-radius: 0;
border-color: var(--hf-ui-border) !important;
color: var(--hf-heading) !important;
}
/*
* The catalog page's own copy control, `snippets/install-command.jsx`. It
* draws Mintlify's clipboard and check icons, so it is styled from the same
* tokens as the sitewide button above and kept next to it: one visual
* language for the two copy affordances a reader meets on the same page.
*
* The button is the whole 44px cell rather than a plate inside a larger box,
* because here the row it sits in has a border and a background of its own —
* the cell is already a shape, so lighting it is the hover.
*/
.hf-install-copy {
display: grid;
place-items: center;
flex-shrink: 0;
width: 44px;
background-color: transparent;
transition: background-color 100ms ease;
}
.hf-install-copy:hover {
background-color: color-mix(in srgb, var(--hf-text) 10%, transparent);
}
/* Both icons occupy the same cell, so the swap is a crossfade in place and
nothing in the row moves or resizes. */
.hf-install-copy > svg {
grid-area: 1 / 1;
color: var(--hf-text-secondary);
transition:
opacity 180ms ease,
color 100ms ease;
}
.hf-install-copy:hover > svg {
color: var(--hf-text);
}
.hf-install-copy > .hf-install-copy-check {
opacity: 0;
}
.hf-install-copy[data-copied="true"] > .hf-install-copy-clipboard {
opacity: 0;
}
/* Brand green, the colour Mintlify's own check is drawn in. The selector
carries one more class than the `:hover` rule above so the check keeps its
colour while the pointer is still on the button it was just clicked with. */
.hf-install-copy[data-copied="true"] > .hf-install-copy-check {
opacity: 1;
color: var(--hf-brand);
}
@media (prefers-reduced-motion: reduce) {
.hf-install-copy > svg {
transition-duration: 0s;
}
}
.hf-install-copy:focus-visible {
outline: 2px solid var(--hf-brand);
outline-offset: -6px;
border-radius: 14px;
}
/* The live region that says "Copied". Visually hidden rather than
`display: none`, which would take it out of the accessibility tree. */
.hf-install-copy-status {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
/* ── Selection ── */
::selection {
background: var(--hf-selection-bg);
}
/* ── Links ── */
#content-area :where(p, li, td, blockquote) a:not([class]) {
border-bottom: 1px solid color-mix(in srgb, var(--hf-brand) 72%, transparent);
color: inherit;
text-decoration: none;
}
#content-area :where(p, li, td, blockquote) a:not([class]):hover {
border-bottom-color: var(--hf-brand);
color: var(--hf-brand);
}
/* ── Documentation navigation ── */
/*
* Keep Aspen's full-width header, but place its desktop controls on one row:
* logo → section tabs → search → actions. Mobile keeps Mintlify's layout.
*/
@media (min-width: 1024px) {
#navbar {
height: 3rem;
}
#navbar > div:has(.nav-tabs) {
display: grid;
grid-template-columns: max-content max-content minmax(10.25rem, 1fr) max-content;
column-gap: 1rem;
align-items: center;
height: 3rem;
}
#navbar > div:has(.nav-tabs) > .relative,
#navbar > div:has(.nav-tabs) > .relative > div:first-child,
#navbar > div:has(.nav-tabs) > .relative > div:first-child > div:first-child {
display: contents;
}
#navbar > div:has(.nav-tabs) > .relative > div:first-child > div:first-child > div:first-child {
grid-column: 1;
grid-row: 1;
}
#navbar div:has(> .nav-tabs) {
grid-column: 2;
grid-row: 1;
height: 3rem;
padding: 0;
}
#navbar .nav-tabs {
align-items: center;
gap: 0.25rem;
height: 3rem;
}
/* Use the same quiet pill treatment as Mintlify's own documentation. */
#navbar .nav-tabs-item {
height: 2.25rem !important;
padding: 0 0.8rem;
border-radius: 999px;
color: var(--hf-text);
transition:
background-color 140ms ease,
color 140ms ease;
}
#navbar .nav-tabs-item:hover {
background: color-mix(in srgb, var(--hf-heading) 6%, transparent);
color: var(--hf-heading);
}
#navbar .nav-tabs-item.text-primary {
background: color-mix(in srgb, var(--hf-heading) 9%, transparent);
color: var(--hf-heading) !important;
}
#navbar .nav-tabs-item > .absolute.bottom-0 {
display: none;
}
#navbar div:has(> #search-bar-entry) {
grid-column: 3;
grid-row: 1;
min-width: 0;
}
#navbar .topbar-right-container {
grid-column: 4;
grid-row: 1;
}
#sidebar-content {
top: 3rem !important;
height: calc(100vh - 3rem) !important;
}
/* Keep the repository compact, but retain its useful live star count. */
#navbar a[title="heygen-com/hyperframes"] {
width: 7.5rem;
min-width: 7.5rem;
height: 2.25rem;
padding: 0 0.75rem;
justify-content: center;
}
#navbar a[title="heygen-com/hyperframes"] > span.truncate {
display: none;
}
#navbar a[title="heygen-com/hyperframes"] > span:not(.truncate) {
display: flex !important;
color: var(--hf-heading);
font-variant-numeric: tabular-nums;
}
/*
* Mintlify removes the live count for roughly one animation frame during
* client-side navigation. Keep a truthful placeholder in its place so the
* control does not collapse while the live count reloads.
*/
#navbar a[title="heygen-com/hyperframes"]:not(:has(> span:not(.truncate)))::after {
color: var(--hf-heading);
content: "★";
font-variant-numeric: tabular-nums;
}
}
/* The native gutter was almost 15px wide. Keep the rail quiet and compact. */
#navigation-items {
scrollbar-color: color-mix(in srgb, var(--hf-text) 30%, transparent) transparent;
scrollbar-gutter: auto !important;
scrollbar-width: thin;
}
#navigation-items::-webkit-scrollbar {
width: 5px;
}
#navigation-items::-webkit-scrollbar-track {
background: transparent;
}
#navigation-items::-webkit-scrollbar-thumb {
border-radius: 999px;
background: color-mix(in srgb, var(--hf-text) 30%, transparent);
}
#navigation-items::-webkit-scrollbar-thumb:hover {
background: color-mix(in srgb, var(--hf-text) 46%, transparent);
}
/* Preserve a useful search field on smaller desktop widths. */
@media (min-width: 1024px) and (max-width: 1199px) {
#navbar #assistant-entry {
display: none;
}
}
/* Every structural hairline (header bottom, content rules, footer) is the palette's line,
* never a light gray that would draw a pale stripe on the paper. */
[class*="border-gray-200"],
[class*="border-gray-100"] {
border-color: var(--hf-ui-border) !important;
}
div.h-px.bg-gray-100 {
background-color: var(--hf-ui-border) !important;
}
/* Keep the floating agent input noticeable against the page background. */
#body-content .chat-assistant-floating-input > div > div {
border-color: var(--hf-border-color-light) !important;
background-color: var(--hf-background-light) !important;
box-shadow: var(--hf-floating-input-shadow);
}
/*
* Match the navigation rhythm and active-page rail used on the main docs.
* Each link owns one rail segment, so the current page can highlight only
* its segment. These rules are visual only; groups remain non-collapsible.
*/
#navigation-items .sidebar-group-header {
color: var(--hf-text);
font-size: 0.875rem;
font-weight: 500;
line-height: 1.25rem;
}
#navigation-items .sidebar-group {
padding-left: 0;
}
#navigation-items .sidebar-group::before {
content: none;
}
#navigation-items .sidebar-group > li {
margin-bottom: 0;
}
#navigation-items .sidebar-group > li + li {
margin-top: 0 !important;
}
#navigation-items .sidebar-group > li > a {
width: calc(100% - 1rem);
margin-left: 1rem;
padding: 0.375rem 0.75rem 0.375rem 1rem;
border-left: 1px solid var(--hf-sidebar-rail);
border-radius: 0;
background: transparent !important;
color: var(--hf-sidebar-text);
}
#navigation-items .sidebar-group > li > a:hover {
background: transparent !important;
color: var(--hf-heading);
}
#navigation-items .sidebar-group > li[data-active="true"] > a,
#navigation-items .sidebar-group > li[data-active-nav-item="true"] > a,
#navigation-items .sidebar-group > li > a[aria-current="page"] {
border-left-color: currentColor;
background: var(--hf-chip) !important;
border-radius: 0 999px 999px 0;
color: var(--hf-heading);
font-weight: 500;
}
/* Aspen inserts horizontal separators; main uses the same space without a rule. */
#navigation-items div:has(> .sidebar-group) + div {
height: 2rem;
padding: 0;
}
#navigation-items div:has(> .sidebar-group) + div > * {
display: none;
}
/*
* Aspen assumes a 96px header and fades scrolled navigation before it reaches
* that boundary. Our header is 48px; align the sticky sidebar to it and let
* links clip exactly at the header instead of disappearing early.
*/
#navigation-items,
#navigation-items [data-id] {
-webkit-mask-image: none !important;
mask-image: none !important;
}
/* Catalog texture examples */
.hf-texture-preview-panel {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
margin: 24px 0 40px;
}
.hf-texture-preview-card {
min-width: 0;
border: 1px solid rgba(127, 127, 127, 0.22);
border-radius: 8px;
padding: 16px;
background: #101010;
}
.hf-texture-preview-label {
margin-bottom: 12px;
color: rgba(255, 255, 255, 0.6);
font-size: 12px;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.hf-texture-preview-shadow {
filter: drop-shadow(1px 2px 1px rgba(0, 0, 0, 0.48));
}
.hf-texture-preview-word {
color: #fff;
font-family: Impact, "Arial Black", sans-serif;
font-size: 42px;
line-height: 0.9;
letter-spacing: 0;
text-align: center;
text-transform: uppercase;
white-space: nowrap;
-webkit-mask-image: var(--mask-url);
mask-image: var(--mask-url);
-webkit-mask-size: cover;
mask-size: cover;
-webkit-mask-position: center;
mask-position: center;
-webkit-mask-mode: luminance;
mask-mode: luminance;
}
.hf-texture-animate-demo {
border: 1px solid rgba(127, 127, 127, 0.22);
border-radius: 8px;
padding: 22px;
margin: 20px 0 24px;
background: linear-gradient(90deg, rgba(255, 255, 255, 0.54) 1px, transparent 1px), #f1f1f1;
background-size: 44px 100%;
}
.hf-texture-animate-meta {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 18px;
}
.hf-texture-animate-label {
min-width: 0;
color: rgba(24, 24, 24, 0.62);
font-size: 13px;
line-height: 1.2;
}
.hf-texture-animate-class {
max-width: 62%;
padding: 2px 6px;
border: 1px solid rgba(24, 24, 24, 0.12);
border-radius: 6px;
background: rgba(255, 255, 255, 0.5);
color: rgba(24, 24, 24, 0.78);
font-size: 11px;
line-height: 1.3;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.hf-texture-animate-shadow {
filter: drop-shadow(1px 2px 1px rgba(0, 0, 0, 0.48));
}
.hf-texture-animate-word {
color: #181818;
font-family: Impact, "Arial Black", sans-serif;
font-size: 92px;
line-height: 0.9;
letter-spacing: 0;
text-align: center;
text-transform: uppercase;
white-space: nowrap;
-webkit-mask-image: var(--mask-url);
mask-image: var(--mask-url);
-webkit-mask-size: 180% 180%;
mask-size: 180% 180%;
-webkit-mask-position: 0% 50%;
mask-position: 0% 50%;
-webkit-mask-mode: luminance;
mask-mode: luminance;
animation: hf-texture-mask-pan 2.1s ease-in-out infinite alternate;
}
@keyframes hf-texture-mask-pan {
from {
-webkit-mask-position: 0% 50%;
mask-position: 0% 50%;
}
to {
-webkit-mask-position: 100% 50%;
mask-position: 100% 50%;
}
}
.hf-texture-example-groups {
display: grid;
gap: 32px;
margin: 20px 0 40px;
}
.hf-texture-example-groups > div,
.hf-texture-example-card {
min-width: 0;
}
.hf-texture-example-title {
margin: 0 0 10px;
font-size: 14px;
font-weight: 600;
}
.hf-texture-example-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
gap: 16px;
}
.hf-texture-example-card {
border: 1px solid rgba(127, 127, 127, 0.22);
border-radius: 8px;
padding: 20px;
background: #f1f1f1;
}
.hf-texture-example-meta {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 14px;
}
.hf-texture-example-label {
min-width: 0;
color: rgba(24, 24, 24, 0.62);
font-size: 13px;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.hf-texture-example-class {
max-width: 62%;
padding: 2px 6px;
border: 1px solid rgba(24, 24, 24, 0.12);
border-radius: 6px;
background: rgba(255, 255, 255, 0.5);
color: rgba(24, 24, 24, 0.78);
font-size: 11px;
line-height: 1.3;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.hf-texture-example-shadow {
filter: drop-shadow(1px 2px 1px rgba(0, 0, 0, 0.48));
}
.hf-texture-example-word {
color: #181818;
font-family: Impact, "Arial Black", sans-serif;
font-size: 54px;
line-height: 0.9;
letter-spacing: 0;
text-align: center;
text-transform: uppercase;
white-space: nowrap;
-webkit-mask-image: var(--mask-url);
mask-image: var(--mask-url);
-webkit-mask-size: cover;
mask-size: cover;
-webkit-mask-position: center;
mask-position: center;
-webkit-mask-mode: luminance;
mask-mode: luminance;
}
.hf-texture-example-usage {
display: flex;
align-items: flex-start;
gap: 6px;
min-width: 0;
margin-top: 14px;
padding-top: 12px;
border-top: 1px solid rgba(24, 24, 24, 0.1);
color: rgba(24, 24, 24, 0.56);
font-size: 12px;
line-height: 1.3;
}
.hf-texture-example-usage code {
min-width: 0;
color: rgba(24, 24, 24, 0.82);
font-size: 11px;
line-height: 1.3;
white-space: normal;
overflow-wrap: anywhere;
}
/* Portrait proof clips should read as examples inside the page, not become the
* page. Landscape films keep the full content width; only explicitly marked
* portrait media gets this compact, centered treatment. */
.hf-portrait-video {
display: block;
width: auto;
max-width: min(100%, 18rem);
max-height: min(32rem, 68vh);
margin: 0.75rem auto 0;
border-radius: 0.5rem;
background: #111;
}
/* Full narrated films use a quiet custom control layer over the native video
* engine. Preview loops remain plain muted videos. */
.hf-docs-video-block {
width: 100%;
}
.hf-docs-video-block[data-portrait="true"] {
width: min(100%, 18rem);
margin: 0.75rem auto 0;
}
.hf-docs-video-block[data-portrait="true"] .hf-docs-video {
aspect-ratio: 9 / 16;
max-height: min(32rem, 68vh);
}
/*
* Mintlify loads custom React snippets after the page shell. Reserve the
* film's real shape so the unloaded component never flashes as a thin Frame
* rail, then let the hydrated player and chapter guide size themselves.
*/
.hf-docs-video-frame {
width: 100%;
aspect-ratio: 16 / 9;
overflow: hidden;
border-radius: 0.75rem;
background: #070707;
}
.hf-docs-video-frame:has(.hf-docs-video-block) {
aspect-ratio: auto;
overflow: visible;
border-radius: 0;
background: transparent;
}
.hf-docs-video {
position: relative;
aspect-ratio: 16 / 9;
overflow: hidden;
border-radius: 0.75rem;
background: #070707;
color: #fff;
isolation: isolate;
outline: none;
}@media (max-width: 720px) {}
@media (max-width: 520px) {}
.hf-docs-video:focus-visible {
box-shadow: 0 0 0 3px color-mix(in srgb, var(--hf-video-accent) 78%, transparent);
}
.hf-docs-video video {
display: block;
width: 100%;
height: 100%;
margin: 0 !important;
background: #070707;
object-fit: contain;
cursor: pointer;
}
.hf-docs-video-hero-play {
position: absolute;
top: 50%;
left: 50%;
display: flex;
align-items: center;
justify-content: center;
width: 3.35rem;
height: 3.35rem;
padding: 0;
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 50%;
background: rgba(8, 8, 8, 0.56);
color: #fff;
font: inherit;
cursor: pointer;
transform: translate(-50%, -50%);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.3);
z-index: 3;
}
.hf-docs-video-hero-play:hover {
border-color: var(--hf-video-accent);
background: rgba(8, 8, 8, 0.78);
}
.hf-docs-video-hero-play:focus-visible,
.hf-docs-video-control:focus-visible,
.hf-docs-video-rate:focus-visible,
.hf-docs-video-progress:focus-visible {
outline: 2px solid var(--hf-video-accent);
outline-offset: 2px;
}
.hf-docs-video-hero-icon {
display: grid;
width: 2rem;
height: 2rem;
flex: 0 0 auto;
place-items: center;
border-radius: 0;
background: transparent;
color: #fff;
}
.hf-docs-video-hero-icon svg {
width: 1.25rem;
height: 1.25rem;
margin-left: 0.1rem;
fill: currentColor;
}
.hf-docs-video-controls {
position: absolute;
right: 0;
bottom: 0;
left: 0;
display: grid;
gap: 0.45rem;
padding: 3.75rem 1rem 0.78rem;
background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.84));
opacity: 1;
transform: translateY(0);
visibility: visible;
transition:
opacity 160ms ease,
transform 160ms ease,
visibility 0s linear;
z-index: 2;
}
.hf-docs-video-controls[data-visible="false"] {
pointer-events: none;
opacity: 0;
transform: translateY(0.4rem);
visibility: hidden;
transition:
opacity 160ms ease,
transform 160ms ease,
visibility 0s linear 160ms;
}
.hf-docs-video-progress {
width: 100%;
height: 1rem;
margin: 0;
border: 0;
background: transparent;
cursor: pointer;
appearance: none;
-webkit-appearance: none;
}
/* Timecode bubble that tracks the pointer along the progress bar. It is a label,
not a thumbnail: rendering a second <video> here made every page with a film
download the whole file twice. */
.hf-docs-video-scrub-preview {
position: absolute;
bottom: 3.6rem;
left: clamp(2rem, var(--hf-video-preview-x), calc(100% - 2rem));
border-radius: 0.35rem;
background: rgba(0, 0, 0, 0.82);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.38);
pointer-events: none;
opacity: 1;
transform: translate(-50%, 0);
transition:
opacity 120ms ease,
transform 120ms ease;
z-index: 4;
}
.hf-docs-video-scrub-preview[data-visible="false"] {
visibility: hidden;
opacity: 0;
transform: translate(-50%, 0.3rem);
}
.hf-docs-video-scrub-preview span {
display: block;
padding: 0.16rem 0.4rem;
color: #fff;
font-variant-numeric: tabular-nums;
font-size: 0.7rem;
line-height: 1.2;
}
.hf-docs-video-progress::-webkit-slider-runnable-track {
height: 0.22rem;
border-radius: 999px;
background: linear-gradient(
to right,
var(--hf-video-accent) 0,
var(--hf-video-accent) var(--hf-video-progress),
rgba(255, 255, 255, 0.34) var(--hf-video-progress),
rgba(255, 255, 255, 0.34) 100%
);
}
.hf-docs-video-progress::-moz-range-track {
height: 0.22rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.34);
}
.hf-docs-video-progress::-moz-range-progress {
height: 0.22rem;
border-radius: 999px;
background: var(--hf-video-accent);
}
.hf-docs-video-progress::-webkit-slider-thumb {
width: 0.85rem;
height: 0.85rem;
margin-top: -0.315rem;
border: 2px solid #121212;
border-radius: 50%;
background: var(--hf-video-accent);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
appearance: none;
-webkit-appearance: none;
}
.hf-docs-video-progress::-moz-range-thumb {
width: 0.85rem;
height: 0.85rem;
border: 2px solid #121212;
border-radius: 50%;
background: var(--hf-video-accent);
}
.hf-docs-video-control-row {
display: flex;
align-items: center;
gap: 0.3rem;
min-width: 0;
}
.hf-docs-video-control,
.hf-docs-video-rate {
display: grid;
height: 2rem;
min-width: 2rem;
padding: 0;
place-items: center;
border: 0;
border-radius: 0.45rem;
background: transparent;
color: rgba(255, 255, 255, 0.92);
font: inherit;
cursor: pointer;
}
.hf-docs-video-control:hover,
.hf-docs-video-rate:hover {
background: rgba(255, 255, 255, 0.13);
color: #fff;
}
.hf-docs-video-control svg {
width: 1.2rem;
height: 1.2rem;
fill: currentColor;
}
.hf-docs-video-rate {
min-width: 2.75rem;
padding: 0 0.45rem;
font-size: 0.75rem;
font-weight: 650;
}
.hf-docs-video-time {
margin-left: 0.2rem;
color: rgba(255, 255, 255, 0.82);
font-variant-numeric: tabular-nums;
font-size: 0.74rem;
line-height: 1;
white-space: nowrap;
}
.hf-docs-video-time span {
color: rgba(255, 255, 255, 0.46);
}
.hf-docs-video-spacer {
flex: 1 1 auto;
}
.hf-docs-video-spinner {
position: absolute;
top: 50%;
left: 50%;
width: 2rem;
height: 2rem;
margin: -1rem 0 0 -1rem;
border: 2px solid rgba(255, 255, 255, 0.28);
border-top-color: var(--hf-video-accent);
border-radius: 50%;
animation: hf-docs-video-spin 700ms linear infinite;
z-index: 3;
}
@keyframes hf-docs-video-spin {
to {
transform: rotate(360deg);
}
}
@media (max-width: 520px) {
.hf-docs-video-hero-play {
width: 3rem;
height: 3rem;
}
.hf-docs-video-hero-icon {
width: 2rem;
height: 2rem;
}
.hf-docs-video-controls {
gap: 0.25rem;
padding: 2.75rem 0.6rem 0.42rem;
}
.hf-docs-video-scrub-preview {
bottom: 3.2rem;
}
.hf-docs-video-time {
margin-left: 0;
font-size: 0.67rem;
}
.hf-docs-video-rate {
min-width: 2.45rem;
padding: 0 0.25rem;
}
}
@media (prefers-reduced-motion: reduce) {
.hf-docs-video-controls {
transition: none;
}
.hf-docs-video-spinner {
animation: none;
}
.hf-docs-video-scrub-preview {
transition: none;
}
}
@media (max-width: 860px) {
.hf-texture-preview-panel {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 520px) {
.hf-texture-preview-panel {
grid-template-columns: 1fr;
}
.hf-texture-preview-word {
font-size: 40px;
}
.hf-texture-animate-meta {
align-items: flex-start;
flex-direction: column;
}
.hf-texture-animate-class {
max-width: 100%;
}
.hf-texture-animate-word {
font-size: 56px;
}
}
@media (prefers-reduced-motion: reduce) {
.hf-texture-animate-word {
animation: none;
}
}
/* Hide the section/group label ("Start here", etc.) that the theme renders
* above every page title. It repeats the sidebar grouping and adds noise on
* every page; each page leads with its own H1 instead. */
.eyebrow {
display: none;
}
/* ── UX-pass tweaks (Ular): brand the Playground CTA, align the logo ── */
@media (min-width: 1024px) {
/* Line the logo up with the sidebar text (was flush at the navbar padding, 16px further left). */
#navbar a[href*="/introduction"] {
margin-left: 16px;
}
/* The Download pill is ink with paper text, like hyperframes.dev's `.sr-pill`. */
#navbar a.group > span.bg-primary-dark {
background: var(--hf-heading) !important;
border-radius: 999px;
}
#navbar a.group:has(> span.bg-primary-dark),
#navbar a.group:has(> span.bg-primary-dark) span:not(.bg-primary-dark),
#navbar a.group:has(> span.bg-primary-dark) svg {
color: var(--hf-background) !important;
font-weight: 700;
}
}
/* Frame mode (every catalog page) renders no `main#content-container`, so it loses
* that element's `px-5 lg:pr-10 lg:pl-[5.5rem]` and sits flush against the sidebar.
* These are those same values, nothing new. */
header.is-frame ~ #body-content #content-area {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
@media (min-width: 1024px) {
header.is-frame ~ #body-content #content-area {
padding-left: 5.5rem;
padding-right: 2.5rem;
}
}
/* An image set beside the text it explains (magazine style); full width on narrow screens. */
.hf-aside {
float: right;
width: 46%;
margin: 0.25rem 0 1rem 1.5rem;
border-radius: 0.5rem;
border: 1px solid rgb(0 0 0 / 0.08);
}
.dark .hf-aside {
border-color: rgb(255 255 255 / 0.1);
}
@media (max-width: 640px) {
.hf-aside {
float: none;
width: 100%;
margin: 0.5rem 0 1rem;
}
}
/* A row of portrait films with a caption under each (explainer styles and similar) */
.hf-shelf { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; margin: 1.25rem 0 2rem; }
.hf-shelf p { margin: 0.5rem 0 0; font-size: 0.875rem; line-height: 1.45; }
@media (max-width: 640px) { .hf-shelf { grid-template-columns: minmax(0, 1fr); } }
/* Two results side by side (comparisons) */
.hf-versus { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; margin: 1.25rem 0; }
.hf-versus p { margin: 0 0 0.4rem; font-size: 0.9375rem; }
@media (max-width: 640px) { .hf-versus { grid-template-columns: minmax(0, 1fr); } }
/* Short looping clips that show where a control is, floated beside the text that names it */
.hf-spot { aspect-ratio: 16 / 10; object-fit: cover; border-radius: 0.6rem; background: rgb(0 0 0 / 0.06);
box-shadow: 0 0 0 1px rgb(0 0 0 / 0.08); margin: 0.25rem 0 1rem 1.25rem; }
.dark .hf-spot { box-shadow: 0 0 0 1px rgb(255 255 255 / 0.1); }
h2 { clear: both; }
.hf-spot.hf-spot-inline { width: 100%; margin: 0; }
/* The header is frosted glass over the paper. */
#navbar > div.bg-background-light {
background: var(--hf-glass) !important;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
@media (min-width: 1024px) {
#navbar .nav-tabs-item.text-primary {
background: var(--hf-chip);
}
}
/* Headlines: hyperframes.dev's heavy, tight TT Norms. */
#page-title {
font-size: clamp(2.25rem, 4vw, 3.5rem);
font-weight: 700;
line-height: 1.02;
letter-spacing: -0.045em;
color: var(--hf-heading);
}
#content-area :is(h2, h3) {
color: var(--hf-heading);
}
#content-area h2 {
font-weight: 700;
letter-spacing: -0.035em;
}
/* The page's one-line description reads like hyperframes.dev's subtitle: light and larger. */
div:has(> div > #page-title) + .prose > p {
font-size: 1.375rem;
font-weight: 300;
line-height: 1.35;
letter-spacing: -0.02em;
color: var(--hf-heading);
}
/* Cards are the app's cards on the paper: near-white, hairline, its card shadow. */
html:not(.dark) #content-area .card {
background: var(--hf-background-light) !important;
border-color: var(--hf-ui-border) !important;
box-shadow: var(--hf-floating-input-shadow);
}
/* Calm callouts are a card on the paper (a Night card in dark mode); their icon keeps its colour.
* Warnings and danger keep Mintlify's tint so they still stand out. */
.callout:is([data-callout-type="note"], [data-callout-type="info"], [data-callout-type="tip"], [data-callout-type="check"]) {
background: var(--hf-background-light) !important;
border-color: var(--hf-ui-border) !important;
color: var(--hf-text) !important;
}
.callout:is([data-callout-type="note"], [data-callout-type="info"], [data-callout-type="tip"], [data-callout-type="check"]) :where(p, div, code) {
color: inherit !important;
}
/* Catalog pages draw with their own --ve-* greys; on the paper they take the app's values. */
html:not(.dark) .hf-ve {
--ve-fg: var(--hf-text);
--ve-muted: var(--hf-text-secondary);
--ve-line: var(--hf-border-color-light);
--ve-surface: var(--hf-background-light);
--ve-sunken: var(--hf-background);
--ve-hover: var(--hf-chip);
--ve-on-bg: var(--hf-heading);
--ve-on-fg: var(--hf-background);
--ve-ring: var(--hf-border-color-light);
}
/* ── One palette for every colour on the page ──
* Mintlify draws text, borders, fills and step markers from its gray scale; these are the
* same lightness steps on the Studio app's warm hue (oklch chroma 0.006, hue 70), so
* gray-900 is the app's --ink. Shared by light and dark mode. */
:root {
--gray-50: 246 242 239;
--gray-100: 241 237 234;
--gray-200: 226 222 219;
--gray-300: 209 205 202;
--gray-400: 162 159 155;
--gray-500: 114 112 108;
--gray-600: 82 80 77;
--gray-700: 65 63 60;
--gray-800: 39 37 34;
--gray-900: 25 23 20;
--gray-950: 12 10 8;
/* Read by snippets that fall back to neutral greys. */
--border-color: var(--hf-border-color);
--code-block-background: var(--hf-code-bg);
}
/* In light mode the mid grays go darker so small text passes 4.5:1 (icons 3:1) on the paper:
* the app's gray-500 step would read 4.3:1 there. */
html:not(.dark) {
--gray-400: 108 105 102;
--gray-500: 80 77 74;
--gray-600: 67 65 62;
}
/* Article text: the typography plugin's cool grays become the same tokens. */
.prose {
--tw-prose-body: var(--hf-text);
--tw-prose-headings: var(--hf-heading);
--tw-prose-lead: var(--hf-text-secondary);
--tw-prose-links: var(--hf-heading);
--tw-prose-bold: var(--hf-heading);
--tw-prose-counters: var(--hf-text-secondary);
--tw-prose-bullets: var(--hf-text-tertiary);
--tw-prose-hr: var(--hf-border-color);
--tw-prose-quotes: var(--hf-heading);
--tw-prose-quote-borders: var(--hf-border-color);
--tw-prose-captions: var(--hf-text-secondary);
--tw-prose-code: var(--hf-heading);
--tw-prose-th-borders: var(--hf-border-color-light);
--tw-prose-td-borders: var(--hf-border-color);
--tw-prose-invert-body: var(--hf-text);
--tw-prose-invert-headings: var(--hf-heading);
--tw-prose-invert-lead: var(--hf-text-secondary);
--tw-prose-invert-links: var(--hf-heading);
--tw-prose-invert-bold: var(--hf-heading);
--tw-prose-invert-counters: var(--hf-text-secondary);
--tw-prose-invert-bullets: var(--hf-text-tertiary);
--tw-prose-invert-hr: var(--hf-border-color);
--tw-prose-invert-quotes: var(--hf-heading);
--tw-prose-invert-quote-borders: var(--hf-border-color);
--tw-prose-invert-captions: var(--hf-text-secondary);
--tw-prose-invert-code: var(--hf-heading);
--tw-prose-invert-th-borders: var(--hf-border-color-light);
--tw-prose-invert-td-borders: var(--hf-border-color);
}
html.dark .hf-ve {
--ve-fg: #f5f3f1;
--ve-muted: #b8b6b4;
--ve-line: rgb(245 243 241 / 0.1);
--ve-surface: #272522;
--ve-sunken: #24211e;
--ve-hover: #2f2c29;
--ve-on-bg: #f5f3f1;
--ve-on-fg: #201e1c;
--ve-ring: rgb(245 243 241 / 0.16);
}
/* Scrollbars, the install box and other small chrome take the same tokens. */
[data-component-part="scroll-area-scrollbar"] {
background: var(--hf-chip) !important;
}
[data-component-part="scroll-area-scrollbar"] > div {
background: color-mix(in srgb, var(--hf-heading) 28%, transparent) !important;
}
.hf-install-command {
border-color: var(--hf-ui-border) !important;
background: var(--hf-code-bg) !important;
}
/* Body copy in dark mode is the app's second ink, not Mintlify's dim gray-400. */
.dark .mdx-content {
color: var(--hf-text);
}
/* Footer links and "Powered by" read at the secondary ink (Mintlify's 50% ink fails on the paper). */
#footer a,
#footer :where(p, span, div) {
color: var(--hf-text-secondary);
}
#footer a:hover {
color: var(--hf-heading);
}
/* Table rules use the same lines: the header rule a touch stronger than the rows. */
#content-area thead {
border-bottom-color: var(--hf-border-color-light) !important;
}
#content-area tbody tr {
border-bottom-color: var(--hf-ui-border) !important;
}
/* ── Code colours: the browser editor's (packages/studio theme.css --color-code-*) ──
* Mintlify highlights code with fixed themes (GitHub light, VS Code dark) and its hosted build ignores a custom
* code theme, so each of those themes' colours is mapped by role to the editor's colour for the same role. */
/* Plain code text (GitHub light's default ink) is the page ink. */
html:not(.dark) pre [style*="color: rgb(31, 35, 40)"],
html:not(.dark) pre[style*="color: rgb(31, 35, 40)"] {
color: var(--hf-text) !important;
}
html:not(.dark) pre span[style*="color: rgb(10, 48, 105)"] {
color: oklch(0.468 0.142 143) !important;
}
html:not(.dark) pre span[style*="color: rgb(207, 34, 46)"] {
color: oklch(0.509 0.211 329) !important;
}
html:not(.dark) pre span[style*="color: rgb(110, 119, 129)"] {
color: oklch(0.48 0.009 279) !important;
}
html:not(.dark) pre span[style*="color: rgb(130, 80, 223)"],
html:not(.dark) pre span[style*="color: rgb(149, 56, 0)"] {
color: oklch(0.492 0.193 263) !important;
}
html:not(.dark) pre span[style*="color: rgb(5, 80, 174)"] {
color: oklch(0.495 0.13 50) !important;
}
html:not(.dark) pre span[style*="color: rgb(17, 99, 41)"] {
color: oklch(0.48 0.12 92) !important;
}
.dark pre span[style*="--shiki-dark: #CE9178"] {
color: oklch(0.793 0.11 133) !important;
}
.dark pre span[style*="--shiki-dark: #569CD6"],
.dark pre span[style*="--shiki-dark: #C586C0"] {
color: oklch(0.829 0.164 318) !important;
}
.dark pre span[style*="--shiki-dark: #DCDCAA"] {
color: oklch(0.805 0.121 245) !important;
}
.dark pre span[style*="--shiki-dark: #9CDCFE"] {
color: oklch(0.856 0.145 17) !important;
}
.dark pre span[style*="--shiki-dark: #6A9955"] {
color: oklch(0.806 0.03 262) !important;
}
.dark pre span[style*="--shiki-dark: #B5CEA8"],
.dark pre span[style*="--shiki-dark: #4FC1FF"] {
color: oklch(0.815 0.11 50) !important;
}
.dark pre span[style*="--shiki-dark: #D7BA7D"] {
color: oklch(0.805 0.1 92) !important;
}
.dark pre span[style*="--shiki-dark: #808080"] {
color: var(--hf-text-tertiary) !important;
}
/* Code blocks sit on the code token (frosted cream in light mode, the Night field in dark), not the theme's own. */
[class*="dark:bg-codeblock"],
html.dark body .code-block-background,
.code-block {
background-color: var(--hf-code-bg) !important;
}
pre.shiki {
background-color: transparent !important;
}
/* The fade that hides long lines under the copy button fades into the same code token. */
.code-block-fade-overlay {
background-image: linear-gradient(to right, transparent, var(--hf-code-bg) 24px) !important;
}
/* 30 Days: a numbered syllabus, one row per lesson, the film previews on hover */
.hf-days { list-style: none; margin: 1rem 0 2rem; padding: 0; border-top: 1px solid var(--hf-ui-border); }
.hf-day { display: grid; grid-template-columns: 3.25rem minmax(0, 1fr) 10.5rem; gap: 1.25rem; align-items: center;
padding: 0.9rem 0; border-bottom: 1px solid var(--hf-ui-border); margin: 0; }
.hf-day-n { font-size: 1.75rem; font-weight: 600; line-height: 1; letter-spacing: -0.02em; color: var(--hf-text-tertiary);
font-variant-numeric: tabular-nums; }
.hf-day-title { font-weight: 600; font-size: 1rem; color: inherit; text-decoration: none; }
.hf-day-title:hover { text-decoration: underline; text-underline-offset: 3px; }
.hf-day-text p { margin: 0.2rem 0 0; font-size: 0.875rem; line-height: 1.45; color: var(--hf-text-secondary); }
.hf-day-film { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 0.5rem; background: var(--hf-surface2); }
@media (max-width: 640px) {
.hf-day { grid-template-columns: 2.25rem minmax(0, 1fr) 6.5rem; gap: 0.75rem; }
.hf-day-n { font-size: 1.25rem; }
}
.hf-day-play { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; border-radius: 0.5rem; }
.hf-day-play:focus-visible { outline: 2px solid var(--hf-brand); outline-offset: 2px; }
/* Showcase rows: two tracks of films drifting in opposite directions, each track twice its films for a seamless loop. */
.hf-film-rows {
display: grid;
gap: 0.6rem;
margin: 1.25rem 0 1.5rem;
overflow: hidden;
border-radius: 0.6rem;
mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
}
.hf-film-row {
overflow: hidden;
}
.hf-film-track {
display: flex;
width: max-content;
cursor: grab;
/* Vertical swipes still scroll the page; sideways ones drag the row (film-rows.jsx). */
touch-action: pan-y;
}
.hf-film-track.is-dragging {
cursor: grabbing;
user-select: none;
}
.hf-film-card {
position: relative;
height: 11.5rem;
margin: 0 0.6rem 0 0;
padding: 0;
border: 0;
border-radius: 0.5rem;
overflow: hidden;
background: #1a1a1a;
cursor: pointer;
flex: none;
}
.hf-film-card video {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.hf-film-card:focus-visible {
outline: 2px solid var(--hf-brand);
outline-offset: 2px;
}
.hf-film-label {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 1.2rem 0.6rem 0.45rem;
font-size: 0.72rem;
line-height: 1.25;
text-align: left;
color: #fff;
background: linear-gradient(transparent, rgb(0 0 0 / 0.7));
}
.hf-film-label b {
display: block;
font-weight: 600;
opacity: 0.75;
text-transform: uppercase;
letter-spacing: 0.06em;
font-size: 0.62rem;
}
.hf-film-dialog {
position: fixed;
inset: 0;
margin: auto;
height: fit-content;
width: min(92vw, 1100px);
padding: 0;
border: 0;
border-radius: 0.75rem;
background: #111;
color: #fff;
}
.hf-film-dialog::backdrop {
background: rgb(0 0 0 / 0.7);
}
.hf-film-dialog video {
display: block;
width: 100%;
max-height: 80vh;
background: #000;
}
.hf-film-dialog-bar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
padding: 0.6rem 0.9rem;
font-size: 0.85rem;
}
.hf-film-dialog-bar button {
font: inherit;
color: inherit;
background: transparent;
border: 1px solid rgb(255 255 255 / 0.4);
border-radius: 999px;
padding: 0.25rem 0.8rem;
cursor: pointer;
}
@media (prefers-reduced-motion: reduce) {
.hf-film-track {
cursor: auto;
touch-action: auto;
}
.hf-film-row {
overflow-x: auto;
}
}
@media (max-width: 640px) {
.hf-film-card {
height: 9rem;
}
}
.hf-film-pause { display: block; margin: 0.5rem 0 0 auto; padding: 0.25rem 0.75rem; border: 1px solid var(--hf-border-color-light);
border-radius: 999px; font-size: 0.8125rem; font-weight: 600; background: transparent; color: inherit; }
/* Remix shelves are columns that each stack their cards, so cards of different shapes leave no holes. */
.hf-remix-shelf {
columns: 2 16rem;
column-gap: 1rem;
}
.hf-remix-shelf.is-tall {
columns: 3 9.5rem;
}
.hf-remix-shelf > * {
break-inside: avoid;
margin-bottom: 1rem;
}
/* Remix cards in the docs palette: an app card on the paper (a Night card in dark mode), ink text, ink pill. */
.hf-remix-card { background: var(--hf-background-light); border-color: var(--hf-ui-border); backdrop-filter: blur(12px); }
.hf-remix-media { background: var(--hf-surface2); }
.hf-remix-name { color: var(--hf-heading); }
.hf-remix-credit, .hf-remix-help { color: var(--hf-text-secondary); }
.hf-remix-credit a { color: inherit; }
.hf-remix-btn { background: var(--hf-heading); color: var(--hf-background); }