/* ===========================================================================
   MOBIFCUK — REDESIGN LAYER

   Loaded last, after all-responsive-metal.css, from template_custom/
   include_header_general.tpl. Everything the site looks like is in this file.
   Nothing here edits a vendor stylesheet, so a KVS update cannot wipe it.

   MOBILE FIRST, LITERALLY
   ~90% of traffic is phones, so every base rule below is the phone rule and
   the media queries only ever add. The vendor sheet works the other way round
   — it is a desktop layout that shrinks — which is why phones were getting
   the tightest spacing on the smallest screen. See the html font-size note.

   HOW IT STAYS COMPATIBLE
   The KVS markup and JS are untouched. That constrains the design in three
   places worth knowing about before editing:

     - `.navigation button` toggles `.open` on `.navigation` (vendor JS).
       The drawer, its close button and its scrim are all <button>s so the
       whole off-canvas menu runs on that one handler.
     - `.lazy-load` + `data-original` load thumbnails. Never set the real src.
     - Pagination links are real <a href> with `data-action="ajax"` layered on
       top. Style them, never replace them — the catalogue past page 1 is only
       crawlable because those hrefs exist.

   Sections
     1  Tokens
     2  Root, base, reset
     3  Layout shell
     4  Header + off-canvas drawer
     5  Section headings + sort controls
     6  Video cards
     7  Model / studio / category cards
     8  Sidebar
     9  Pagination
     10 Video detail page
     11 Pornstar profile page
     12 Affiliate CTAs
     13 Studio logo slots
     14 Footer
     15 Advertising slots
     16 Tablet and desktop
   =========================================================================== */


/* ---------------------------------------------------------------------------
   1  TOKENS
   Two ramps: neutrals for surfaces, one warm accent for anything actionable.
   A single accent is a deliberate constraint — on a page that is 95%
   photography, a second brand colour just competes with the thumbnails.
   --------------------------------------------------------------------------- */

:root {
	/* surfaces, darkest to lightest */
	--bg:            #0b0b0d;
	--surface:       #131317;
	--surface-2:     #1a1a20;
	--surface-3:     #23232b;
	--line:          #2a2a33;
	--line-soft:     rgba(255, 255, 255, .07);

	/* text */
	--fg:            #f5f5f7;
	--fg-muted:      #9a9aa6;
	--fg-dim:        #6e6e7a;

	/* accent */
	--accent:        #f6d78a;
	--accent-hover:  #ffe7ad;
	--accent-ink:    #1a140c;
	--accent-soft:   rgba(246, 215, 138, .18);
	/* Metal fill. Flat --accent stays the text colour; chips and buttons use this. */
	--accent-fill: linear-gradient(168deg, #fff8dc 0%, #ffe59a 16%, #f3c84a 42%, #fff1b4 50%, #e4ae32 68%, #c89022 100%);
	--accent-fill-hover: linear-gradient(168deg, #fffdf4 0%, #fff0c0 28%, #ffd86a 70%, #f0c04a 100%);

	/* status */
	--good:          #35d08a;
	--bad:           #ff4d5e;

	/* shape */
	--r-sm:  8px;
	--r-md:  12px;
	--r-lg:  16px;
	--r-pill: 999px;

	/* spacing — the page gutter is a variable because three components need
	   to break out of it to go full-bleed on phones */
	--gutter: 12px;

	/* the sticky header's height, used for scroll-margin so in-page anchors
	   do not land underneath it */
	--head-h: 56px;

	--ease: cubic-bezier(.4, 0, .2, 1);

	/* legacy names kept so the CTA rules below read the same as before */
	--cta-bg: var(--accent-fill);
	--cta-fg: var(--accent-ink);

	/* shadow colour, so light mode can use a real shadow instead of a smear */
	--shadow: rgba(0, 0, 0, .5);
	--scrim: rgba(0, 0, 0, .6);

	/* CTA glow. Spelled out per theme rather than derived from --accent,
	   because rgba() cannot take a hex token — same reason --accent-soft is
	   written out twice. */
	--glow:      rgba(243, 196, 64, .55);
	--glow-soft: rgba(243, 196, 64, .30);

	/* The CTA's resting drop shadow — accent-tinted, so it needs a light
	   variant too. Distinct from --shadow, which is neutral elevation. */
	--cta-shadow: rgba(232, 176, 48, .32);

	/* Off-canvas drawer: translucent and blurred over the page behind it. Its
	   own token rather than reusing --surface because it carries alpha, and
	   because there has to be an opaque fallback for engines with no
	   backdrop-filter — at .82 with no blur the nav labels sit on top of
	   whatever thumbnail happens to be behind them. */
	--drawer-bg:        rgba(21, 21, 26, .82);
	--drawer-bg-opaque: #15151a;
}

/* ---------------------------------------------------------------------------
   LIGHT THEME

   The whole reason section 1 is tokens rather than literal colours: light mode
   is a palette swap, not a second stylesheet. Every component below reads
   these, so nothing here needs to know what a video card looks like.

   `data-theme` is stamped on <html> by an inline script in the <head> before
   first paint — see include_header_general.tpl. Anything keyed off a class on
   <body> instead would flash the wrong theme on every navigation.

   Contrast checked against WCAG AA: --fg on --bg is 16.1:1, --fg-muted on --bg
   is 5.9:1, and --accent-ink on --accent is 8.4:1. The accent darkens slightly
   in light mode. Gold #d6b06a is for dark surfaces and filled buttons with
   dark ink. Text on white uses #7a5424, which clears 4.5:1.
   --------------------------------------------------------------------------- */

:root[data-theme="light"] {
	--bg:            #ffffff;
	--surface:       #f5f5f7;
	--surface-2:     #eeeef1;
	--surface-3:     #e3e3e8;
	--line:          #dcdce2;
	--line-soft:     rgba(0, 0, 0, .09);

	--fg:            #16161a;
	--fg-muted:      #5c5c68;
	--fg-dim:        #77778a;

	--accent:        #7a5208;
	--accent-hover:  #684408;
	--accent-ink:    #1a140c;
	--accent-soft:   rgba(212, 160, 23, .22);
	/* Same metal as dark mode. Cream stays a stripe, so the pill still
	   has a gold edge on white. Text links stay #7a5208. */
	--accent-fill: linear-gradient(168deg, #e0b03a 0%, #f8d56a 18%, #fff3c4 34%, #f0c24a 48%, #e8b03a 64%, #c89022 100%);
	--accent-fill-hover: linear-gradient(168deg, #f0c24a 0%, #fff6d0 16%, #ffe59a 40%, #f3c84a 62%, #d4a017 100%);

	--good:          #067a4a;
	--bad:           #c8102e;

	--shadow: rgba(16, 16, 26, .16);
	--scrim:  rgba(16, 16, 26, .45);

	--drawer-bg:        rgba(255, 255, 255, .86);
	--drawer-bg-opaque: #f7f7f9;

	/* Lower alpha than dark mode on purpose. A glow is light spilling onto a
	   dark ground; at the same strength over white it reads as a dirty smudge
	   rather than as brightness. */
	--glow:      rgba(201, 146, 40, .32);
	--glow-soft: rgba(201, 146, 40, .16);

	--cta-shadow: rgba(201, 146, 40, .20);
}


/* ---------------------------------------------------------------------------
   2  ROOT, BASE, RESET

   The vendor sheet ramps html font-size DOWN as the viewport narrows —
   62.5% → 58.5% → 52.5% → 47.5%. Every rem-based padding and gap in the theme
   therefore collapses to roughly three quarters of its intended size exactly
   where fingers need it most: 2rem of heading padding becomes 9.5px on a
   phone. Pinning it to 62.5% everywhere makes 1rem = 10px at every width, so
   spacing stays constant and this file can reason in px.
   --------------------------------------------------------------------------- */

html {
	font-size: 62.5%;
	background: var(--bg);
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

body {
	/* System stack. The vendor sheet pulls Roboto through an @import, which
	   cannot start downloading until the CSS itself has parsed — so text would
	   wait two round trips to paint. Nothing here depends on that font. */
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
	             "Helvetica Neue", Arial, sans-serif;
	font-size: 15px;
	line-height: 1.45;
	color: var(--fg);
	background: var(--bg);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; }

/* Focus that is visible on a dark background but never on a mouse click. */
:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 2px;
	border-radius: 2px;
}

.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 2000;
	padding: 12px 18px;
	background: var(--accent-fill);
	color: var(--accent-ink);
	font-weight: 700;
	border-radius: 0 0 var(--r-sm) 0;
}
.skip-link:focus { left: 0; }

/* Anchor targets clear the sticky header. */
[id] { scroll-margin-top: calc(var(--head-h) + 12px); }

/* Kill the tap-highlight flash and the 300ms delay on every control. */
a, button, .toggle-button, .search-button,
.ico-fav-0, .ico-fav-1, [data-action] {
	-webkit-tap-highlight-color: transparent;
	touch-action: manipulation;
}

/* The player iframe needs the same thing, and the list above missed it.
   Tapping inside a nested document makes Chrome Android paint its highlight —
   rgba(51,181,229,.4) — on the IFRAME ELEMENT itself, in that element's own
   shape. The iframe carries border-radius: 10px, so every play/pause tap drew
   a light rounded rectangle over the video. Killing the highlight inside the
   player document does not stop it: the parent owns the iframe box.

   touch-action is deliberately not set here. The player has its own drag
   gestures on the progress bar, and manipulation is the parent's call to make
   for its own controls, not for a document it does not own. */
iframe,
.embed-wrap,
.player-holder,
.player {
	-webkit-tap-highlight-color: transparent;
}


/* ---------------------------------------------------------------------------
   3  LAYOUT SHELL
   --------------------------------------------------------------------------- */

.container {
	background: var(--bg);
	/* vendor sets overflow:hidden here, which would clip the sticky header if
	   the header were inside it. It is not — it sits above .container — but
	   leaving this visible also lets sticky sub-headers work later. */
	overflow: visible;
	max-width: 1600px;
}

.content,
.center-hold {
	width: auto;
	max-width: none;
	padding-left: var(--gutter);
	padding-right: var(--gutter);
	box-sizing: border-box;
}

/* The sidebar comes FIRST in the markup and vendor reorders it with flex
   `order: 2`. Keep a flex context here or it renders above the videos —
   on the homepage that put a wall of category chips before the first
   thumbnail. */
.main-content {
	display: flex;
	flex-direction: column;
	/* Both of these cancel vendor rules meant for its horizontal layout, and
	   both are load-bearing in a column:
	     flex-wrap: wrap        — wraps items into a SECOND COLUMN, which made
	                              the content 706px wide inside a 375px screen
	     align-items: flex-start — shrink-wraps each row to its content instead
	                              of filling the width */
	flex-wrap: nowrap;
	align-items: stretch;
	padding: 0 0 24px;
}

.main-container {
	order: 1;
	min-width: 0;
	width: auto;
}

/* Secondary on a phone: below the videos, not above them. */
.sidebar {
	order: 2;
	width: auto;
	margin: 24px 0 0;
	padding: 0;
	background: transparent;
	box-shadow: none;
	border-radius: 0;
}

.box { margin-bottom: 8px; }

.empty-content {
	padding: 32px var(--gutter);
	color: var(--fg-muted);
	text-align: center;
}

/* Prose blocks — the SEO copy under the listings and the footer text. These
   carry inline links that inherited plain white from vendor, so in light mode
   they were invisible: white on white, and still clickable, which is worse
   than merely ugly. Body copy takes the muted tone, links take the accent. */
.content .text,
.box .text {
	color: var(--fg-muted);
	font-size: 15px;
	line-height: 1.65;
}
.content .text p,
.box .text p { margin: 0 0 12px; }
/* `.content > p` is deliberate. The stored copy is `<p class="text">` wrapping
   another `<p>`, which is invalid — the parser closes the outer paragraph and
   hoists the inner one out as a sibling, so the links end up in a bare <p>
   directly under .content and no `.text a` selector can ever reach them.
   Worth fixing in the content itself; styling the real structure meanwhile. */
.content .text a,
.box .text a,
.content > p a {
	color: var(--accent);
	text-decoration: none;
	font-weight: 600;
}
.content > p {
	color: var(--fg-muted);
	font-size: 15px;
	line-height: 1.65;
	margin: 0 0 12px;
}
.no-touch .content .text a:hover,
.no-touch .box .text a:hover,
.no-touch .content > p a:hover { text-decoration: underline; text-underline-offset: 2px; }


/* ---------------------------------------------------------------------------
   4  HEADER + OFF-CANVAS DRAWER

   Phone: a 56px sticky bar — menu, logo, search — and nothing else. The old
   header spent ~380px (47% of a 812px viewport) on a logo row, a full-width
   search field and a lone hamburger before a single thumbnail appeared.
   --------------------------------------------------------------------------- */

.site-head {
	position: sticky;
	top: 0;
	z-index: 900;
	background: var(--bg);
	border-bottom: 1px solid var(--line);
}

/* One line at every width: logo, search, theme toggle, menu.
   The search field is the only thing that flexes; everything else is a fixed
   touch target, so the bar reflows by squeezing the field rather than by
   wrapping or by shrinking the tap targets below 40px.

   No backdrop-filter here. It was on this element for the frosted effect, but
   backdrop-filter — like filter and transform — makes an element a containing
   block for position:fixed descendants, and the drawer now lives inside this
   bar. With it on, the drawer resolved `top:0; bottom:0` against the 56px
   header and rendered as a 56px sliver. An opaque background is also the
   right call in light mode, where a blur over white looks like a smudge. */
.site-head__bar {
	display: flex;
	align-items: center;
	gap: 8px;
	height: var(--head-h);
	padding: 0 10px;
	max-width: 1600px;
	margin: 0 auto;
	box-sizing: border-box;
}

/* Vendor ships `.search { order: 2 }` and `.logo { order: 1 }` for its own
   header. Left alone they reshuffle this row — the theme toggle jumped ahead
   of the search field. Pin every item explicitly. */
.site-head__bar > .logo      { order: 0; }
.site-head__bar > .search    { order: 1; }
.site-head__bar > .theme-toggle { order: 2; }
.site-head__bar > .site-head__nav { order: 3; }

/* .navigation now wraps only the menu button, the drawer and the scrim — the
   theme toggle is deliberately outside it, because the vendor handler fires on
   every <button> it contains. Here it is just a state container for `.open`,
   so it has to go back to being a plain inline box: left as the vendor's flex
   bar it would stretch and push the search field off the row. */
.site-head .navigation {
	display: block;
	flex: 0 0 auto;
	background: none;
	border: 0;
	padding: 0;
	margin: 0;
	min-height: 0;
	width: auto;
	text-align: left;
}
.site-head__nav { flex: 0 0 auto; display: block; }

/* menu + theme buttons: 42px, at the accessibility floor for a touch target
   while still leaving the search field room on a 320px screen */
/* Scoped through .site-head because the vendor selector is `.navigation
   button` — a class plus an element beats a lone class, so a bare
   `.site-head__menu { width: 42px }` lost and the icon rendered 29px wide. */
.site-head .site-head__menu,
.site-head .theme-toggle {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 42px;
	min-width: 42px;
	height: 42px;
	padding: 0;
	margin: 0;
	border: 0;
	border-radius: var(--r-sm);
	background: none;
	color: var(--fg);
	cursor: pointer;
	transition: background-color .15s var(--ease), color .15s var(--ease);
}
.no-touch .site-head__menu:hover,
.no-touch .theme-toggle:hover { background: var(--surface-2); }
.site-head__menu:active,
.theme-toggle:active { background: var(--surface-3); }

/* --- theme toggle --------------------------------------------------------
   Both icons ship in the markup and CSS picks one, so the button is never
   briefly wrong the way a JS innerHTML swap would be. Sun means "you are in
   dark, tap for light"; moon means the reverse — the icon shows the
   destination, which is the convention people already read correctly. */
.theme-toggle__sun  { display: none; }
.theme-toggle__moon { display: block; }

:root[data-theme="dark"] .theme-toggle__sun  { display: block; }
:root[data-theme="dark"] .theme-toggle__moon { display: none; }

.no-touch .theme-toggle:hover { color: var(--accent); }

/* hamburger: three bars, no library */
.site-head .site-head__menu .icon {
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 4px;
	width: 20px;
	height: 20px;
	margin: 0;
	background: none;
}
.site-head .site-head__menu .ico-bar {
	display: block;
	width: 20px;
	height: 2px;
	border-radius: 2px;
	background: currentColor;
	margin: 0;
}
/* Vendor animates the bars into an X and recolours them #276fdb on open. The
   drawer already has its own close button, so that X is a duplicate — and in
   the theme's blue rather than our accent. Keep it in currentColor. */
.site-head .navigation.open .site-head__menu .ico-bar { background: currentColor; }

.site-head .logo {
	display: flex;
	align-items: center;
	justify-content: flex-start;
	flex: 0 0 auto;
	min-width: 0;
	margin: 0;
	padding: 0;
	float: none;
	width: auto;
	height: auto;
	/* vendor ships .logo { order: 1 }, which would throw it past the search */
	order: 0;
}
.site-head .logo a { display: block; line-height: 0; }

/* One logo per theme. Dark theme gets the white wordmark, light gets the near
   black one; the gradient mark is the same in both. */
.site-head .logo .logo-dark  { display: block; }
.site-head .logo .logo-light { display: none; }
:root[data-theme="light"] .site-head .logo .logo-dark  { display: none; }
:root[data-theme="light"] .site-head .logo .logo-light { display: block; }
.site-head .logo img {
	display: block;
	/* The asset is 181x42 (4.31:1). A flat 108px cap rendered it 108x25 — never
	   cropped, but only 25px tall in a 56px bar, which reads as squeezed.
	   min() ties the cap to the viewport instead of a fixed guess, so 320px
	   still leaves the search field room while anything wider gets a logo in
	   proportion to the bar:
	     320px -> 109px wide, 25px tall
	     375px -> 128px wide, 30px tall
	     412px+ -> 140px wide, 32px tall (capped)
	   No object-fit needed: with width and height auto plus max-*, the image
	   scales proportionally on its own. */
	max-width: min(140px, 34vw);
	max-height: 34px;
	width: auto;
	height: auto;
}

/* --- drawer ---------------------------------------------------------------
   Moved with transform, never display:none, so every nav link stays in the
   raw HTML at every viewport for crawlers. */

.site-drawer {
	position: fixed;
	top: 0;
	left: 0;
	bottom: 0;
	z-index: 1001;
	width: min(86vw, 330px);
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 0 0 24px;
	/* Translucent + blurred, so the page reads through the panel. Safe to put
	   backdrop-filter here: it makes an element a containing block for
	   position:fixed DESCENDANTS, and the drawer has none. It is exactly why
	   this cannot go back on .site-head, which contains the drawer. */
	background: var(--drawer-bg);
	backdrop-filter: blur(14px) saturate(150%);
	-webkit-backdrop-filter: blur(14px) saturate(150%);
	border-right: 1px solid var(--line);
	overflow-y: auto;
	overscroll-behavior: contain;
	-webkit-overflow-scrolling: touch;
	transform: translate3d(-100%, 0, 0);
	visibility: hidden;
	transition: transform .24s var(--ease), visibility .24s var(--ease);
	box-shadow: 0 0 40px var(--shadow);
}
/* Scoped through .site-head and stated as `transform: none` rather than a
   zero translate. This rule has to beat every vendor rule that touches the
   nav, and the drawer sits inside .site-head__bar now, so it is worth being
   unambiguous: a plain `.navigation.open .site-drawer` is only (0,3,0) and
   competes with vendor selectors of the same weight. */
.site-head .navigation.open .site-drawer,
.navigation.open .site-drawer {
	transform: none;
	visibility: visible;
}

/* No blur support: fall back to an opaque panel. At .82 alpha with nothing
   blurring behind it, the nav labels sit directly on whatever thumbnail
   happens to be there. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	.site-drawer { background: var(--drawer-bg-opaque); }
}

.site-drawer__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	height: var(--head-h);
	padding: 0 8px 0 16px;
	border-bottom: 1px solid var(--line);
	position: sticky;
	top: 0;
	/* transparent, not --surface: an opaque strip here would sit as a solid
	   block on top of the translucent panel */
	background: transparent;
	z-index: 1;
}
.site-drawer__title {
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .1em;
	color: var(--fg-dim);
}
.site-drawer__close {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border: 0;
	padding: 0;
	background: none;
	color: var(--fg);
	border-radius: var(--r-sm);
	cursor: pointer;
}
.no-touch .site-drawer__close:hover { background: var(--surface-2); }

.site-drawer__scrim {
	position: fixed;
	inset: 0;
	z-index: 1000;
	width: 100%;
	height: 100%;
	padding: 0;
	border: 0;
	background: var(--scrim);
	opacity: 0;
	visibility: hidden;
	cursor: default;
	transition: opacity .24s var(--ease), visibility .24s var(--ease);
}
.navigation.open .site-drawer__scrim { opacity: 1; visibility: visible; }

/* --- search --------------------------------------------------------------- */

/* The drawer is a flex column and several of these carry a vendor `order`
   (.search ships order:2), which shuffled the panel — the search field landed
   below the account buttons. Pin the order to the reading order. */
/* Several of these carry a vendor `order`, which shuffles the panel. Pin the
   order to the reading order. `flex: 0 0 auto` is load-bearing too: vendor
   ships growth rules meant for a horizontal header bar, and in this column
   they stretch a child down the whole panel. */
.site-drawer > .site-drawer__head { order: 0; flex: 0 0 auto; }
.site-drawer > .primary           { order: 2; flex: 0 0 auto; }
.site-drawer > .secondary         { order: 3; flex: 0 0 auto; }
.site-drawer > .member-links      { order: 4; flex: 0 0 auto; }
.site-drawer > .network           { order: 5; flex: 0 0 auto; }

/* The search lives in the bar now, not the drawer, and it is the only flexible
   item on that row. min-width:0 is what lets it shrink instead of forcing the
   row wider than the viewport on a 320px screen. */
.site-head .search {
	flex: 1 1 auto;
	min-width: 0;
	margin: 0;
	padding: 0;
	width: auto;
	float: none;
	position: static;
}
.site-head .search form {
	display: flex;
	align-items: stretch;
	gap: 0;
	background: var(--surface-2);
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	overflow: hidden;
	transition: border-color .15s var(--ease);
}
.site-head .search form:focus-within { border-color: var(--accent); }

/* Vendor stretches .search-text to the height of its container, which in a
   column drawer means the full panel — a 630px-tall search field. Selected via
   the form id because the vendor rule outranks a two-class selector. */
#search_form .search-text {
	flex: 1 1 auto;
	position: static;
	min-width: 0;
	width: auto;
	height: auto;
	min-height: 0;
	max-height: none;
	margin: 0;
	padding: 0;
	background: none;
	border: 0;
}
#search_form .search-text input {
	width: 100%;
	height: 40px;
	margin: 0;
	padding: 0 2px 0 14px;
	border: 0;
	background: none;
	color: var(--fg);
	/* 16px is the iOS Safari threshold — below it, focusing the field zooms
	   the whole page and the user has to pinch back out */
	font-size: 16px;
	box-sizing: border-box;
	-webkit-appearance: none;
	appearance: none;
}
#search_form .search-text input::placeholder { color: var(--fg-dim); }
#search_form .search-text input::-webkit-search-cancel-button { filter: invert(1) opacity(.5); }

/* Vendor renders this as a <span> and submits the form from JS. It carries the
   word "Search" as a label; on a phone that word costs ~60px of a row that has
   none to spare, so the icon replaces it and the text moves to aria-label. */
.site-head .search-button {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 42px;
	min-width: 0;
	height: 40px;
	margin: 0;
	padding: 0;
	background: var(--accent-fill);
	color: var(--accent-ink);
	font-size: 0;
	border: 0;
	border-radius: 0;
	cursor: pointer;
	text-indent: 0;
	overflow: visible;
	white-space: nowrap;
}
.site-head .search-button::before,
.site-head .search-button::after { display: none; }
.no-touch .site-head .search-button:hover { background: var(--accent-fill-hover); }

/* --- drawer nav ----------------------------------------------------------- */

/* The vendor mobile menu positions these lists absolutely and pins them to a
   narrow fixed width. Left alone, .primary rendered 135px wide at y=819 —
   off the bottom of the drawer — and .secondary took the flow slot at the top,
   so the drawer looked empty. Everything here goes back into normal flow. */
.site-head .primary,
.site-head .secondary {
	display: block;
	position: static;
	top: auto;
	left: auto;
	right: auto;
	bottom: auto;
	margin: 6px 0 0;
	padding: 0 8px;
	list-style: none;
	float: none;
	background: none;
	border: 0;
	width: auto;
	min-width: 0;
	max-width: none;
	height: auto;
	max-height: none;
	overflow: visible;
	visibility: visible;
	opacity: 1;
	transform: none;
}
.site-head .secondary:empty { display: none; }
.site-head .primary > li,
.site-head .secondary > li {
	display: block;
	position: static;
	float: none;
	width: auto;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
}
/* Scoped through .navigation to outrank the vendor rules, which set
   `font-size: 0` and hang an icomoon glyph off ::before — the Home item
   rendered as a lone house icon with its label invisible. */
.site-head .navigation .primary > li > a,
.site-head .navigation .secondary > li > a {
	display: block;
	position: relative;
	padding: 13px 12px;
	border-radius: var(--r-sm);
	color: var(--fg);
	font-size: 15.5px;
	font-weight: 600;
	line-height: 1.2;
	text-align: left;
	text-indent: 0;
	text-decoration: none;
	text-transform: none;
	background: none;
	border: 0;
	height: auto;
	cursor: pointer;
}
.site-head .navigation .primary > li > a::before,
.site-head .navigation .secondary > li > a::before { display: none; }

/* Home is the one nav item the theme turns into a bare icon:
   `#item1 { font-size: 0 }` plus an icomoon house on ::after. An ID beats any
   class selector, so this has to carry an ID to win. A pictogram among six
   word labels is not clearer than the word — give Home its label back. */
.site-head #item1 {
	font-size: 15.5px;
	height: auto;
}
.site-head #item1::after { display: none; }

.no-touch .site-head .navigation .primary > li > a:hover {
	background: var(--surface-2);
	color: var(--fg);
}

.site-head .navigation .primary > li.selected > a {
	background: var(--accent-fill);
	color: var(--accent-ink);
	border: 0;
}
.site-head .navigation .primary > li.highlight > a { color: var(--accent); }

/* nested upload dropdown flattens into an indented sublist in the drawer */
.site-head .primary > li > ul {
	display: block;
	position: static;
	margin: 0 0 0 12px;
	padding: 0;
	list-style: none;
	background: none;
	border: 0;
	box-shadow: none;
	width: auto;
}
.site-head .primary > li > ul > li > a {
	display: block;
	padding: 11px 12px;
	color: var(--fg-muted);
	font-size: 14.5px;
	text-decoration: none;
}

/* account links */
.site-head .member-links {
	margin: 10px 8px 0;
	padding: 14px 0 0;
	border-top: 1px solid var(--line);
	float: none;
	width: auto;
}
.site-head .member-links > ul {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-start;
	gap: 8px;
	margin: 0;
	padding: 0 4px;
	list-style: none;
}
.site-head .member-links > ul > li {
	flex: 0 0 auto;
	width: auto;
	max-width: 100%;
	float: none;
	margin: 0;
	padding: 0;
	border: 0;
	color: var(--fg-muted);
	font-size: 14px;
}
.site-head .member-links > ul > li > a {
	display: block;
	/* vendor pulls this 20px outside its own <li> with a negative right margin,
	   which made Sign up overlap Log in */
	margin: 0;
	padding: 10px 16px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	color: var(--fg);
	font-size: 14px;
	font-weight: 600;
	text-decoration: none;
	background: var(--surface-2);
}
.site-head .member-links > ul > li#signup > a,
.site-head .member-links > ul > li:first-child > a {
	background: var(--accent-fill);
	border-color: var(--accent);
	color: var(--accent-ink);
}
.site-head .member-links .disabled { opacity: .5; }

.site-head .member-links .languages { position: relative; }
.site-head .member-links .languages > ul {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin: 8px 0 0;
	padding: 0;
	list-style: none;
	position: static;
	background: none;
	border: 0;
	box-shadow: none;
}
.site-head .member-links .languages > ul a {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 8px 12px;
	border-radius: var(--r-sm);
	background: var(--surface-2);
	color: var(--fg-muted);
	font-size: 13px;
	text-decoration: none;
}

.site-head .network {
	margin: 14px 12px 0;
	padding-top: 14px;
	border-top: 1px solid var(--line);
	float: none;
	width: auto;
}
.site-head .network strong {
	display: block;
	margin-bottom: 8px;
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: .1em;
	color: var(--fg-dim);
}
.site-head .network ul { margin: 0; padding: 0; list-style: none; }
.site-head .network li { float: none; margin: 0; }
.site-head .network a {
	display: block;
	padding: 9px 0;
	color: var(--fg-muted);
	font-size: 14px;
	text-decoration: none;
}

/* Vendor's old top strip is gone from the markup; make sure any cached copy
   of it cannot reappear as a stray bar. */
.top-links { display: none; }


/* ---------------------------------------------------------------------------
   5  SECTION HEADINGS + SORT

   One pattern for every list heading on the site: heavy tight title, short
   accent rule beneath it. It is what makes a long scroll of near-identical
   thumbnail grids legible as separate sections.
   --------------------------------------------------------------------------- */

.headline {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px 14px;
	position: relative;
	margin: 0 0 14px;
	padding: 26px 0 10px;
	width: auto;
}

.headline h1,
.headline h2 {
	position: relative;
	margin: 0;
	padding-bottom: 11px;
	font-size: 21px;
	font-weight: 800;
	line-height: 1.15;
	letter-spacing: -.02em;
	color: var(--fg);
	text-transform: none;
}

/* The accent rule hangs off the heading, not off .headline. On list pages the
   sort chips live inside .headline too, so a rule on the container bottom
   drew itself under the last row of chips instead of under the title. */
.headline h1::after,
.headline h2::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 40px;
	height: 3px;
	border-radius: 2px;
	background: var(--accent-fill);
}
.headline h1 a,
.headline h2 a { color: inherit; text-decoration: none; }

/* Vendor prefixes sidebar headings with an icomoon glyph that sits right on
   top of the accent rule. The rule is the section marker now, so the glyph is
   redundant — and it is drawn on an absolutely positioned ::before, so it does
   not reflow out of the way on its own. */
.headline .icon,
.headline h2 a.icon,
.headline h1 a.icon {
	background-image: none;
	padding-left: 0;
	text-indent: 0;
}
.headline .icon::before { display: none; }


.headline .more {
	margin-left: auto;
	padding: 8px 14px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	color: var(--fg-muted);
	font-size: 13px;
	font-weight: 600;
	text-decoration: none;
	background: var(--surface-2);
	white-space: nowrap;
}
.no-touch .headline .more:hover { color: var(--fg); border-color: var(--fg-dim); }

.headline .button-info {
	padding: 4px 10px;
	border-radius: var(--r-pill);
	background: var(--surface-3);
	color: var(--fg-muted);
	font-size: 12px;
	font-weight: 700;
}

/* subscribe / generic pill button in a headline */
.headline > a.button {
	margin-left: auto;
	padding: 10px 18px;
	border-radius: var(--r-pill);
	background: var(--accent-fill);
	color: var(--accent-ink);
	font-size: 13.5px;
	font-weight: 700;
	text-decoration: none;
	border: 0;
	height: auto;
	line-height: 1.2;
}
.headline > a.button span { color: inherit; }

/* --- sort dropdowns -------------------------------------------------------
   These are hover-opened menus in the vendor theme, which is unusable on a
   touch screen. Here they scroll horizontally as a row of chips instead: no
   hidden state, one tap per option. */

/* Vendor styles `.sort` as a hover-opened dropdown: a #212121 pill that turns
   #276fdb on :hover. Redesigned here as a row of chips, so the container should
   have no background of its own — left alone, hovering anywhere near the row
   painted a solid blue slab behind the chips. The :hover/:focus override below
   is the part that actually kills it; `background: none` only handles resting
   state. */
.list-sort,
.sort,
.sort:hover,
.sort:focus,
.sort:focus-within {
	display: flex;
	align-items: center;
	gap: 8px;
	position: static;
	margin: 0 0 12px;
	padding: 0;
	border: 0;
	border-radius: 0;
	background: none;
	background-color: transparent;
	color: inherit;
	width: auto;
	min-width: 0;
	float: none;
	height: auto;
	overflow-x: auto;
	overflow-y: hidden;
	scrollbar-width: none;
	-webkit-overflow-scrolling: touch;
}
.sort::-webkit-scrollbar { display: none; }

.sort > .icon { display: none; }

/* Vendor's dropdown caret. It is `position: absolute` and .sort is now
   position:static, so it resolves against whatever ancestor happens to be
   positioned — landing somewhere arbitrary and rotating 180° on hover, which
   reads as the row twitching when the pointer crosses it. There is no dropdown
   to point at any more. */
.sort::before,
.sort::after,
.sort:hover::before { display: none; content: none; }

/* Same trap one level down: the chips are vendor `.sort ul a`, which carries a
   `transition` and gains a background on hover. Pin the transform so a chip
   cannot get promoted to its own layer mid-hover either. */
.sort > ul > li > a,
.sort > ul > li > a:hover,
.no-touch .sort > ul > li > a:hover {
	transform: none;
}

.sort > strong {
	position: relative;
	flex: 0 0 auto;
	padding: 9px 15px;
	/* transparent 1px, matching the chips' real border. Without it the active
	   chip is 2px shorter and narrower than its neighbours, so the row's
	   geometry changes as the active state moves between sort options. */
	border: 1px solid transparent;
	border-radius: var(--r-pill);
	background: var(--accent-fill);
	color: var(--accent-ink);
	font-size: 13.5px;
	font-weight: 700;
	line-height: 1.2;
	white-space: nowrap;
}
/* the caret belonged to the hover dropdown these chips replaced */
.sort > strong::after,
.sort > strong::before { display: none; }

.sort > ul,
.sort:hover > ul,
.sort:hover ul,
.sort:focus > ul,
.sort:focus-within > ul {
	display: flex;
	align-items: center;
	gap: 8px;
	position: static;
	margin: 0;
	padding: 0;
	list-style: none;
	background: none;
	border: 0;
	box-shadow: none;
	width: auto;
	min-width: 0;
	visibility: visible;
	opacity: 1;
	/* THE hover jitter.

	   Vendor: `.sort:hover ul { transform: translateY(0) }` — specificity
	   (0,3,0), which beats a plain `.sort > ul` at (0,2,0). The resting rule
	   sets no transform at all, so on hover this element goes from
	   `transform: none` to a transform. That promotes it to its own compositing
	   layer and re-rasterises it, and the row visibly snaps by a subpixel — the
	   grid underneath appears to jump with it.

	   It is a rendering effect, not a layout one, which is why replaying the
	   hover declarations and measuring geometry never reproduced it: every box
	   stayed exactly where it was. The selectors above have to carry :hover
	   themselves to outrank the vendor rule; `transform: none` at resting
	   specificity alone does not win. */
	transform: none;
	transition: none;
}
.sort > ul > li { float: none; margin: 0; padding: 0; border: 0; }
.sort > ul > li > a,
.related-videos .list-sort a,
.related-videos .list-sort span,
.list-sort > li > a,
.list-sort > li > span {
	display: block;
	padding: 9px 15px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface-2);
	color: var(--fg-muted);
	font-size: 13.5px;
	font-weight: 600;
	text-decoration: none;
	white-space: nowrap;
	cursor: pointer;
}
/* the related-videos filter row inherits its colour from a dark ancestor, so
   it needs the token spelled out rather than left to cascade */
.related-videos .list-sort > li:first-child > span {
	background: var(--accent-fill);
	border-color: var(--accent);
	color: var(--accent-ink);
	font-weight: 700;
}
.no-touch .sort > ul > li > a:hover {
	color: var(--fg);
	border-color: var(--fg-dim);
	background: var(--surface-3);
}


/* ---------------------------------------------------------------------------
   6  VIDEO CARDS

   The highest-leverage surface on the site, so it gets the most attention.

   One column on phones. Two would fit, but a 16:9 thumbnail at 175px wide is
   too small to judge a scene from, and judging the scene is the entire job of
   this component.

   The duration and rating are lifted onto the image without touching the
   template: the <a> becomes a grid, the image is placed at 1/1, and the wrap
   that follows the title is placed at 1/1 as well and bottom-aligned. Vendor
   markup order is .img, .title, .wrap(duration+rating), .wrap(added+views).
   --------------------------------------------------------------------------- */

.list-videos .margin-fix {
	display: grid;
	grid-template-columns: 1fr;
	gap: 24px 12px;
	margin: 0;
	padding: 0;
}

/* Card surface.

   Vendor ships every .item with `box-shadow: -1px 1px 5px rgba(33,33,33,.65)`
   and `border-radius: 0 0 5px 5px` — square top corners, rounded bottom. On a
   near-black page the shadow is invisible and nobody notices. On the light
   theme it draws a hard-edged box around a 12px-rounded thumbnail, which is
   the mismatch that shows up as "a rectangular border under the thumbnail".

   Rather than just cancelling it, this makes the card real: one surface, one
   radius all round, the thumbnail clipped to it, and room under the meta line
   so the text is not sitting on the card's edge. */
.list-videos .item,
.list-models .item,
.list-sponsors .item,
.list-categories .item,
.list-playlists .item,
.list-channels .item {
	background: var(--surface);
	border: 0;
	border-radius: var(--r-md);
	box-shadow: 0 1px 2px var(--shadow);
	overflow: hidden;
	padding: 0 0 12px;
}

.list-videos .item {
	float: none;
	width: auto;
	margin: 0;
	position: relative;
}

.list-videos .item > a {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 0;
	text-decoration: none;
	color: inherit;
	position: relative;
}

.list-videos .item .img {
	grid-area: 1 / 1;
	position: relative;
	width: 100%;
	margin: 0;
	padding: 0;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	/* Top corners only. The card now clips to its own radius, so a fully
	   rounded thumbnail inside it would show the card surface in the two lower
	   corners as small coloured notches. */
	border-radius: var(--r-md) var(--r-md) 0 0;
	background: var(--surface-2);
	/* a flat plate while the lazy-loaded thumb is still a 1px gif */
	box-shadow: inset 0 0 0 1px var(--line-soft);
}

.list-videos .item .img img.thumb {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
	transition: transform .35s var(--ease), opacity .2s linear;
}
.no-touch .list-videos .item:hover .img img.thumb { transform: scale(1.04); }

/* Gradient scrim so white badge text survives a bright thumbnail. */
.list-videos .item .img::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 42%;
	pointer-events: none;
	background: linear-gradient(to top, rgba(0, 0, 0, .78), rgba(0, 0, 0, 0));
	/* Square. The thumbnail's bottom corners are square now that the card clips
	   them, so a rounded scrim left two curved notches of card surface showing
	   through the bottom of every image — very visible on the light theme. */
	border-radius: 0;
}

/* the duration + rating row, lifted onto the image */
.list-videos .item .title + .wrap {
	grid-area: 1 / 1;
	align-self: end;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin: 0;
	padding: 10px;
	pointer-events: none;
}

.list-videos .item .duration {
	float: none;
	margin: 0;
	padding: 4px 8px;
	border-radius: 6px;
	background: rgba(0, 0, 0, .72);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
	color: #fff;
	font-size: 12px;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	line-height: 1.25;
	text-indent: 0;
	background-image: none;
	width: auto;
	height: auto;
}

.list-videos .item .title + .wrap .rating {
	float: none;
	margin: 0;
	padding: 4px 8px;
	border-radius: 6px;
	background: rgba(0, 0, 0, .72);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
	font-size: 12px;
	font-weight: 700;
	line-height: 1.25;
	text-indent: 0;
	background-image: none;
	width: auto;
	height: auto;
}
.list-videos .item .title + .wrap .rating.positive { color: var(--good); }
.list-videos .item .title + .wrap .rating.negative { color: var(--bad); }

/* The theme draws these labels' icons with an icomoon glyph on an absolutely
   positioned ::before. Absolute means it resolves against .img, not the badge,
   so once the badges moved onto the thumbnail the clock and thumb glyphs
   landed on top of the digits — "11:00" read as "1:00". In a pill this small
   the icon is redundant anyway. */
.list-videos .item .title + .wrap .duration::before,
.list-videos .item .title + .wrap .rating::before { display: none; }

/* HD / 4K flag, top-left */
.list-videos .item .is-hd {
	position: absolute;
	top: 8px;
	left: 8px;
	z-index: 2;
	margin: 0;
	padding: 3px 7px;
	border-radius: 5px;
	background: var(--accent-fill);
	color: var(--accent-ink);
	font-size: 10.5px;
	font-weight: 800;
	letter-spacing: .04em;
	line-height: 1.3;
	text-indent: 0;
	width: auto;
	height: auto;
}

/* favourite / watch-later, top-right. 36px targets, always visible on touch
   because there is no hover to reveal them with. */
.list-videos .item .ico-fav-0,
.list-videos .item .ico-fav-1 {
	position: absolute;
	top: 8px;
	z-index: 3;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	margin: 0;
	border-radius: 50%;
	background: rgba(0, 0, 0, .6);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
	background-size: 18px 18px;
	background-position: center;
	background-repeat: no-repeat;
	opacity: .92;
}
.list-videos .item .ico-fav-0 { right: 8px; }
.list-videos .item .ico-fav-1 { right: 52px; }

.list-videos .item .title {
	display: block;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	display: -webkit-box;
	overflow: hidden;
	/* 10px sides now that the card has a surface — at 2px the text sat almost
	   on the card edge */
	margin: 10px 0 0;
	padding: 0 10px;
	max-height: none;
	color: var(--fg);
	font-size: 15px;
	font-weight: 600;
	line-height: 1.35;
	letter-spacing: -.005em;
	text-decoration: none;
}
.no-touch .list-videos .item:hover .title { color: var(--accent); }

/* second wrap: date + views, the quiet line */
.list-videos .item .wrap + .wrap {
	display: flex;
	align-items: center;
	/* generous, because the two halves are pushed apart and a long view count
	   must never end up touching the date */
	gap: 14px;
	margin: 6px 0 0;
	padding: 0 10px;
	color: var(--fg-dim);
	font-size: 12.5px;
}
.list-videos .item .wrap + .wrap .added,
.list-videos .item .wrap + .wrap .views {
	/* the icomoon ::before is absolutely positioned, so this element has to be
	   the containing block or the glyph escapes onto the sibling's text */
	position: relative;
	float: none;
	margin: 0;
	/* 22px, not 19: the icomoon glyph is 14px wide sitting at left:0, so 19
	   left roughly 5px of clearance and the eye almost touched the digits.
	   nowrap + flex-shrink:0 is what keeps "10,000" or "1.2M" on one line —
	   without it a long count wraps under its own icon in a narrow card. */
	padding: 0 0 0 22px;
	color: inherit;
	font-size: inherit;
	line-height: 1.3;
	text-indent: 0;
	width: auto;
	height: auto;
	white-space: nowrap;
	flex: 0 0 auto;
	min-width: 0;
}
/* the date is the half that gives way when the card is too narrow for both */
.list-videos .item .wrap + .wrap .added {
	flex: 0 1 auto;
	overflow: hidden;
	text-overflow: ellipsis;
}
.list-videos .item .wrap + .wrap .added::before,
.list-videos .item .wrap + .wrap .views::before {
	left: 0;
	top: 50%;
	transform: translateY(-50%);
	width: 14px;
	height: 14px;
	font-size: 13px;
	line-height: 1;
	color: inherit;
}
.list-videos .item .wrap + .wrap .views { margin-left: auto; }
.list-videos .item .wrap + .wrap em { font-style: normal; }

/* state overlays */
.list-videos .item .line-private,
.list-videos .item .line-premium,
.list-videos .item .line-disabled,
.list-videos .item .line-error,
.list-videos .item .line-processing {
	position: absolute;
	left: 8px;
	bottom: 8px;
	z-index: 2;
	padding: 3px 8px;
	border-radius: 5px;
	background: rgba(0, 0, 0, .78);
	color: #fff;
	font-size: 11px;
	font-weight: 700;
}


/* ---------------------------------------------------------------------------
   7  MODEL / STUDIO / CATEGORY CARDS

   Pornstars get a 3:4 portrait crop — faces read far better tall than wide,
   and it is what makes the grid scannable at a glance. Two up on a phone.
   --------------------------------------------------------------------------- */

.list-models .margin-fix,
.list-sponsors .margin-fix,
.list-categories .margin-fix,
.list-playlists .margin-fix,
.list-channels .margin-fix {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 22px 12px;
	margin: 0;
	padding: 0;
}

/* padding/background deliberately absent — they are set by the shared card
   rule further up, and repeating `background: none` here silently cancelled it */
.list-models .item,
.list-sponsors .item,
.list-categories .item,
.list-playlists .item,
.list-channels .item {
	float: none;
	width: auto;
	margin: 0;
}

.list-models .item > a,
.list-sponsors .item > a,
.list-categories .item > a,
.list-playlists .item > a,
.list-channels .item > a {
	display: block;
	text-decoration: none;
	color: inherit;
}

.list-models .item .img,
.list-categories .item .img,
.list-playlists .item .img,
.list-channels .item .img {
	position: relative;
	width: 100%;
	height: auto;
	margin: 0;
	padding: 0;
	aspect-ratio: 3 / 4;
	overflow: hidden;
	border-radius: var(--r-md) var(--r-md) 0 0;
	background: var(--surface-2);
	box-shadow: inset 0 0 0 1px var(--line-soft);
}
.list-categories .item .img,
.list-playlists .item .img,
.list-channels .item .img { aspect-ratio: 16 / 9; }

.list-models .item .img img.thumb,
.list-categories .item .img img.thumb,
.list-playlists .item .img img.thumb,
.list-channels .item .img img.thumb {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
	transition: transform .35s var(--ease);
}
.no-touch .list-models .item:hover .img img.thumb { transform: scale(1.05); }

.list-models .item .no-thumb,
.list-categories .item .no-thumb,
.list-playlists .item .no-thumb {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	padding: 8px;
	background: var(--surface-2);
	color: var(--fg-dim);
	font-size: 12.5px;
	text-align: center;
	border-radius: inherit;
}

.list-models .item .title,
.list-sponsors .item .title,
.list-categories .item .title,
.list-playlists .item .title,
.list-channels .item .title {
	display: block;
	margin: 9px 0 0;
	padding: 0 10px;
	color: var(--fg);
	font-size: 14.5px;
	font-weight: 600;
	line-height: 1.3;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.no-touch .list-models .item:hover .title,
.no-touch .list-sponsors .item:hover .title { color: var(--accent); }

.list-models .item .wrap,
.list-sponsors .item .wrap,
.list-categories .item .wrap,
.list-channels .item .wrap {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 3px 0 0;
	padding: 0 10px;
	color: var(--fg-dim);
	font-size: 12.5px;
}
.list-models .item .videos,
.list-sponsors .item .videos,
.list-categories .item .videos,
.list-channels .item .videos {
	/* same icomoon trap as the video cards: the glyph is on an absolutely
	   positioned ::before, so without a containing block here it lands on top
	   of the count and "2 videos" reads as "videos" */
	position: relative;
	float: none;
	margin: 0;
	padding: 0 0 0 19px;
	color: inherit;
	font-size: inherit;
	background: none;
	text-indent: 0;
	width: auto;
	height: auto;
}
.list-models .item .videos::before,
.list-sponsors .item .videos::before,
.list-categories .item .videos::before,
.list-channels .item .videos::before {
	left: 0;
	top: 50%;
	transform: translateY(-50%);
	width: 14px;
	height: 14px;
	font-size: 13px;
	line-height: 1;
	color: inherit;
}
/* The vendor prints a rating chip here that reads "0%" for almost every
   performer, which is noise rather than information. */
.list-models .item .wrap .rating,
.list-sponsors .item .wrap .rating { display: none; }

/* Alphabet strip on /pornstars/ — a horizontal scroller on a phone. */
.alphabet {
	display: flex;
	gap: 6px;
	margin: 0 0 14px;
	padding: 0 0 4px;
	list-style: none;
	overflow-x: auto;
	scrollbar-width: none;
	-webkit-overflow-scrolling: touch;
}
.alphabet::-webkit-scrollbar { display: none; }
.alphabet li { float: none; margin: 0; flex: 0 0 auto; }
.alphabet a,
.alphabet .all {
	display: flex;
	align-items: center;
	justify-content: center;
	min-width: 38px;
	height: 38px;
	padding: 0 10px;
	border: 1px solid var(--line);
	border-radius: var(--r-sm);
	background: var(--surface-2);
	color: var(--fg-muted);
	font-size: 14px;
	font-weight: 600;
	text-decoration: none;
	box-sizing: border-box;
}
.alphabet .selected a,
.no-touch .alphabet a:hover {
	background: var(--accent-fill);
	border-color: var(--accent);
	color: var(--accent-ink);
}


/* ---------------------------------------------------------------------------
   8  SIDEBAR

   On a phone this is a set of link chips under the videos, not a column.
   --------------------------------------------------------------------------- */

.sidebar .headline { padding-top: 22px; }
.sidebar .headline h2 { font-size: 17px; }

.sidebar .list {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}
.sidebar .list li {
	float: none;
	/* vendor sets width:100% here, which turns every chip into a full-width row */
	width: auto;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
}
.sidebar .list li a {
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 9px 14px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface-2);
	color: var(--fg-muted);
	font-size: 14px;
	font-weight: 500;
	text-decoration: none;
	line-height: 1.2;
}
.no-touch .sidebar .list li a:hover {
	color: var(--fg);
	border-color: var(--fg-dim);
	background: var(--surface-3);
}
/* vendor: `.no-touch .sidebar .list a:hover { color: #276fdb }` — restated so
   the chip does not turn the old theme's blue. Latent while enable_sidebar is
   false, but it would come straight back with the sidebar. */
.no-touch .sidebar .list a:hover,
.no-touch .sidebar .list a:hover .rating { color: var(--fg); }
.sidebar .list li a .rating {
	padding: 1px 7px;
	border-radius: var(--r-pill);
	background: var(--surface-3);
	color: var(--fg-dim);
	font-size: 11.5px;
	font-weight: 700;
	float: none;
	margin: 0;
	width: auto;
	height: auto;
	background-image: none;
	text-indent: 0;
}

/* tag cloud */
.tags-cloud .text,
.box.tags-cloud .text {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	padding: 0;
	margin: 0 0 8px;
}
/* The anchors are direct children of `.box.tags-cloud` — there is no `.text`
   wrapper on this page type, so a `.tags-cloud .text a` selector matched
   nothing and the chips inherited plain white. */
.tags-cloud a,
.tags-cloud .text a,
.tags-cloud .text .all,
.tags-cloud .all {
	display: block;
	padding: 8px 13px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface-2);
	/* `.tags-cloud .all` ships #fff on #212121 from vendor — invisible once the
	   chip takes a light background */
	color: var(--fg-muted);
	font-size: 13.5px;
	font-weight: 500;
	text-align: left;
	text-decoration: none;
	line-height: 1.2;
}
.no-touch .tags-cloud .text a:hover { color: var(--fg); border-color: var(--fg-dim); }


/* ---------------------------------------------------------------------------
   9  PAGINATION

   Real <a href> links with data-action="ajax" layered on. Styling only —
   never swap an href for a handler, or the catalogue past page 1 stops being
   crawlable. Same reason $pagination_no_links must stay empty.
   --------------------------------------------------------------------------- */

.pagination,
.pagination-holder {
	margin: 22px 0 8px;
	padding: 0;
	text-align: center;
}

.pagination ul {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}
.pagination li { float: none; margin: 0; padding: 0; }

.pagination li a,
.pagination li span {
	display: flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	height: 44px;
	padding: 0 12px;
	border: 1px solid var(--line);
	border-radius: var(--r-sm);
	background: var(--surface-2);
	color: var(--fg-muted);
	font-size: 15px;
	font-weight: 600;
	text-decoration: none;
	box-sizing: border-box;
	line-height: 1;
}
.no-touch .pagination li a:hover {
	color: var(--fg);
	border-color: var(--fg-dim);
	background: var(--surface-3);
}
.pagination li.page-current a,
.pagination li.page-current span {
	background: var(--accent-fill);
	border-color: var(--accent);
	color: var(--accent-ink);
}


/* ---------------------------------------------------------------------------
   10  VIDEO DETAIL PAGE

   Player first. The title used to sit above it and push the video below the
   fold on a phone; now the player is the first thing on screen and the title
   follows it, which is also how every major platform orders it.
   --------------------------------------------------------------------------- */

/* Vendor lays .block-video out as a flex ROW: the three 300x250 ad slots
   (.table) form a right-hand rail beside the player on a desktop. On a phone
   that row does not wrap, so the rail claimed 920px of a 375px viewport and
   squeezed everything else to nothing — the player rendered 25px wide and the
   CTA, rating bar, tabs and details block all collapsed to 1px.

   Stack it instead, and put the player first. The ad slots keep every
   impression, they just sit under the video rather than on top of it, which
   is also the only way the player is above the fold on a phone. */
.block-video {
	display: flex;
	flex-direction: column;
	/* Vendor sets align-items: flex-start. In a column that shrink-wraps each
	   child to its own content, so .video-holder sized itself to the widest
	   thing inside it — the full-bleed player — and pushed the whole column
	   28px past the page gutter. stretch makes every row the container width. */
	align-items: stretch;
	margin: 0;
}
.block-video > .video-holder { order: 1; }
.block-video > .table        { order: 2; }

.block-video .video-holder {
	order: 1;
	min-width: 0;
	width: auto;
	margin: 0;
	/* Vendor paints this #000. It wraps the CTA, rating bar, tabs and details
	   as well as the player, so in light mode it was a black slab behind half
	   the page. The player keeps its own black — video wants it — but the
	   wrapper should not have one. */
	background: transparent;
	border-radius: 0;
	box-shadow: none;
}
.block-video .table { background: transparent; }

.block-video .player,
.block-video .player-holder {
	margin: 0;
	padding: 0;
	background: #000;
	border-radius: 0;
	overflow: hidden;
	width: auto;
}

/* Full-bleed player on phones: break out of the page gutter. A 16:9 frame at
   375px wide gains 24px of width doing this, which is worth more than the
   rounded corners it costs. */
.block-video .player {
	margin-left: calc(var(--gutter) * -1);
	margin-right: calc(var(--gutter) * -1);
}

.block-video .embed-wrap {
	position: relative;
	width: 100%;
	/* the template sets padding-bottom inline for the true ratio; this is the
	   floor so the box is never zero-height before that applies */
	min-height: 0;
	background: #000;
}
.block-video .embed-wrap iframe,
.block-video .player-holder video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
	display: block;
}

/* Title moves below the player without touching the template: the page is
   .headline then .block-video, so flex ordering on the parent swaps them. */
.content > .headline:has(h1) + .block-video { margin-top: 0; }

.block-video .video-info { margin: 0; padding: 0; }

/* Vendor runs this as a wrapping flex row (.tabs-menu ships `flex: 1 1 100%`
   to claim a line of its own). On a phone the rating row and the tab row ended
   up drawn on top of each other. A column stacks them predictably. */
.block-video .info-holder {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	margin: 0;
	padding: 0;
}

/* --- like / dislike / favourite row -------------------------------------- */

/* .tabs-menu is a child of this row, not a sibling, and takes its own line via
   `flex: 1 1 100%`. So this must wrap — forcing nowrap lays the tabs straight
   over the rating bar. */
.block-video .info-buttons {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-start;
	gap: 10px;
	margin: 14px 0 0;
	padding: 14px 0 0;
	border-top: 1px solid var(--line);
	float: none;
	width: auto;
}

.block-video .rating-container {
	display: flex;
	flex-direction: row;
	flex-wrap: nowrap;
	align-items: center;
	gap: 8px;
	flex: 1 1 auto;
	min-width: 0;
	float: none;
	margin: 0;
	width: auto;
}

.block-video .rate-like,
.block-video .rate-dislike {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 46px;
	height: 46px;
	margin: 0;
	padding: 0;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface-2);
	background-position: center;
	background-repeat: no-repeat;
	background-size: 20px 20px;
	color: transparent;
	font-size: 0;
	text-indent: 0;
	overflow: hidden;
	float: none;
}
.no-touch .block-video .rate-like:hover { border-color: var(--good); }
.no-touch .block-video .rate-dislike:hover { border-color: var(--bad); }

.block-video .rating-container .rating {
	display: flex;
	flex-direction: column;
	gap: 5px;
	float: none;
	margin: 0;
	width: auto;
	min-width: 120px;
}
.block-video .voters {
	color: var(--fg-muted);
	font-size: 13px;
	font-weight: 600;
}
.block-video .scale-holder {
	display: block;
	width: 100%;
	height: 5px;
	border-radius: var(--r-pill);
	background: var(--surface-3);
	overflow: hidden;
	float: none;
	margin: 0;
}
.block-video .scale-holder .scale {
	display: block;
	height: 100%;
	border-radius: inherit;
	background: var(--good);
}
.block-video .scale-holder.negative .scale { background: var(--bad); }

.block-video .btn-favourites {
	position: relative;
	margin-left: auto;
	float: none;
}
.block-video .btn-favourites > .drop {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 46px;
	height: 46px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface-2);
	cursor: pointer;
}

/* --- tabs ---------------------------------------------------------------- */

/* .tabs-menu is a wrapper; the list inside it is what lays the tabs out, and
   vendor gives that list `flex-wrap: wrap; justify-content: center`, which
   stacked three tabs into a 130px-tall centred cascade. One scrollable row. */
.block-video .tabs-menu {
	display: block;
	flex: 1 1 100%;
	width: 100%;
	min-width: 0;
	max-width: 100%;
	margin: 8px 0 0;
	padding: 0;
	border: 0;
}
.block-video .tabs-menu ul,
.block-video .tabs-menu > ul {
	display: flex;
	flex-direction: row;
	flex-wrap: nowrap;
	justify-content: flex-start;
	align-items: center;
	gap: 8px;
	margin: 0;
	padding: 0 0 2px;
	list-style: none;
	overflow-x: auto;
	scrollbar-width: none;
	-webkit-overflow-scrolling: touch;
}
.block-video .tabs-menu ul::-webkit-scrollbar { display: none; }
.block-video .tabs-menu li { float: none; margin: 0; padding: 0; flex: 0 0 auto; }
.block-video .tabs-menu .toggle-button {
	display: block;
	padding: 10px 16px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface-2);
	color: var(--fg-muted);
	font-size: 14px;
	font-weight: 600;
	white-space: nowrap;
	cursor: pointer;
	height: auto;
	line-height: 1.2;
}
.block-video .tabs-menu .toggle-button.active,
.block-video .tabs-menu .active .toggle-button {
	background: var(--accent-fill);
	border-color: var(--accent);
	color: var(--accent-ink);
}

.block-video .tab-content {
	margin: 14px 0 0;
	padding: 0;
	border: 0;
	background: none;
}
.block-video .tab-content.hidden { display: none; }

/* --- details list -------------------------------------------------------- */

.block-details { margin: 0; padding: 0; }

.block-details .info {
	display: flex;
	flex-direction: column;
	gap: 12px;
	margin: 0;
	padding: 0;
}
.block-details .info .item {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 6px 10px;
	float: none;
	margin: 0;
	padding: 0 0 12px;
	width: auto;
	border-bottom: 1px solid var(--line-soft);
	color: var(--fg-muted);
	font-size: 14.5px;
	line-height: 1.5;
}
.block-details .info .item:last-child { border-bottom: 0; padding-bottom: 0; }
.block-details .info .item > span:first-child { color: var(--fg-dim); }

/* Vendor hard-codes #fff on .block-details .item, its <em> values and the
   nested `span em`. Those <em>s hold the actual data — duration, view count,
   date, description — so in light mode the labels rendered and the values
   beside them were invisible. Each selector below out-specifies its vendor
   counterpart; the label keeps the dimmer tone, the value takes full contrast. */
.block-details .info .item,
.block-details .info .item em,
.block-details .info .item span em {
	color: var(--fg);
	font-style: normal;
}
/* Same #3f3f3f problem on the video page: the label half of each detail row.
   The label takes the muted tone, the <em> value beside it takes full
   contrast — set above, and reasserted here so source order cannot flip them. */
.block-details .info .item span { color: var(--fg-muted); }
.block-details .info .item span em,
.block-details .info .item em { color: var(--fg); }

/* Every category / tag / performer link in the details block becomes a chip.
   These are the site's main internal links, so they need to be obvious and
   easy to hit, not 13px underlined text in a run-on sentence. */
.block-details .info .item a {
	display: inline-block;
	padding: 7px 13px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface-2);
	color: var(--fg);
	font-size: 13.5px;
	font-weight: 600;
	text-decoration: none;
	line-height: 1.25;
}
.no-touch .block-details .info .item a:hover {
	border-color: var(--accent);
	color: var(--accent);
}

/* --- screenshots, share, comments ---------------------------------------- */

.block-screenshots .margin-fix {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 10px;
}
.block-screenshots .thumb {
	float: none;
	width: auto;
	margin: 0;
	border-radius: var(--r-sm);
	overflow: hidden;
	aspect-ratio: 16 / 9;
	background: var(--surface-2);
}
.block-screenshots .thumb img { width: 100%; height: 100%; object-fit: cover; }

.block-share .textfield,
.block-textarea textarea,
.block-comments textarea,
.block-comments input[type="text"] {
	width: 100%;
	box-sizing: border-box;
	padding: 12px 14px;
	border: 1px solid var(--line);
	border-radius: var(--r-sm);
	background: var(--surface-2);
	color: var(--fg);
	/* 16px minimum or iOS Safari zooms the page on focus */
	font-size: 16px;
	font-family: inherit;
}
.block-share .textfield:focus,
.block-textarea textarea:focus { border-color: var(--accent); outline: none; }

.block-comments .hint,
.block-video .hint { color: var(--fg-dim); font-size: 13px; }

/* --- related videos ------------------------------------------------------ */

.related-videos { margin-top: 8px; }


/* ---------------------------------------------------------------------------
   11  PORNSTAR PROFILE PAGE

   Rewritten from the 158 lines that had been appended to the vendor
   all-responsive-white.css — a file a KVS update replaces wholesale. Same
   intent, now in this file where it survives, and on the design system.
   --------------------------------------------------------------------------- */

.block-model {
	margin: 0;
	padding: 0;
	background: none;
	border: 0;
}

.block-model .img {
	position: relative;
	float: none;
	width: 100%;
	max-width: 260px;
	height: auto;
	margin: 0 0 18px;
	padding: 0;
	aspect-ratio: 3 / 4;
	overflow: hidden;
	border-radius: var(--r-lg);
	background: var(--surface-2);
	box-shadow: inset 0 0 0 1px var(--line-soft);
}
.block-model .img img.thumb,
.block-model .img img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
}
.block-model .img .no-thumb {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	background: var(--surface-2);
	color: var(--fg-dim);
	font-size: 13px;
	text-align: center;
}

/* A performer with no photo was reserving a 260x345 empty grey rectangle at
   the top of their profile, pushing the bio and facts — the part that does
   have content — most of a screen down. Keep the slot, shrink it. */
.block-model .img:has(.no-thumb) {
	max-width: 150px;
	aspect-ratio: 4 / 3;
}

/* Fact rows. 17px tall rows with no separation were unscannable; each fact
   now gets its own line with a muted label and a solid value. */
/* Vendor lays the facts out as a flex row of `width: 33.33%` items. Cancelling
   that width without replacing the layout lets the rows run together on one
   line — "Country: BrazilActive Since: 2015Age: 29". A grid owns the columns
   explicitly instead: one per row on a phone, two side by side from 768px. */
.block-model .model-list,
.model-list {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	list-style: none;
	margin: 0 0 18px;
	padding: 0;
}
/* Vendor is `.block-model .model-list li { color: #3f3f3f }` — a mid grey
   chosen for the light theme. Against the dark background that measures
   1.87:1, well under the 4.5:1 floor, and it outranks a two-class selector.
   This is a pre-existing contrast failure, not something light mode caused. */
.block-model .model-list li,
.model-list li {
	display: flex;
	flex-wrap: wrap;
	gap: 4px 10px;
	margin: 0;
	padding: 11px 0;
	border-bottom: 1px solid var(--line-soft);
	color: var(--fg-muted);
	width: auto;
	font-size: 14.5px;
	line-height: 1.5;
	float: none;
	width: auto;
	background: none;
}
.model-list li:last-child { border-bottom: 0; }
/* Vendor is `.block-model .model-list li span { color: #fff }`. A two-class
   selector loses to it, so every fact value — country, age, height — was white
   on white in light mode. It only looked fine in dark because #fff happens to
   sit near --fg there. */
.block-model .model-list li span,
.model-list li span { color: var(--fg); font-weight: 600; }
.model-list a {
	color: var(--accent);
	font-weight: 600;
	text-decoration: none;
}
.no-touch .model-list a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* Bio. The source has real paragraph breaks; they render as <p> now instead
   of collapsing into one grey wall. */
.block-model .desc {
	margin: 0 0 18px;
	color: var(--fg-muted);
	font-size: 15.5px;
	line-height: 1.65;
}
.block-model .desc p { margin: 0 0 14px; }
.block-model .desc p:last-child { margin-bottom: 0; }

.block-model .website {
	margin: 0 0 18px;
	color: var(--fg-dim);
	font-size: 14px;
	word-break: break-word;
}
.block-model .website a { color: var(--accent); text-decoration: none; }

/* Official links, as chips with a 44px tap target. */
.model-socials { margin: 0 0 20px; }
.model-socials h3 {
	margin: 0 0 10px;
	font-size: 11.5px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .1em;
	color: var(--fg-dim);
}
.model-socials ul {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}
.model-socials li { float: none; margin: 0; }
.model-socials a {
	display: flex;
	align-items: center;
	gap: 8px;
	min-height: 44px;
	padding: 0 16px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface-2);
	color: var(--fg);
	font-size: 14px;
	font-weight: 600;
	line-height: 1.2;
	text-decoration: none;
}
.no-touch .model-socials a:hover {
	border-color: var(--accent);
	color: var(--accent);
}
.model-socials svg { flex: 0 0 auto; }

/* FAQ. Built in PHP and stored ready-rendered on the model record, so the
   markup is a plain <dl> — question in <dt>, answer in <dd>. It had no styling
   at all and ran together as one block of undifferentiated lines. It also
   backs the FAQPage JSON-LD on this page, so it is worth reading well. */
.model-faq {
	margin: 26px 0 0;
	padding: 20px 0 0;
	border-top: 1px solid var(--line);
}
.model-faq h2 {
	margin: 0 0 14px;
	font-size: 19px;
	font-weight: 800;
	letter-spacing: -.015em;
	color: var(--fg);
}
.model-faq dl { margin: 0; }
.model-faq dt {
	margin: 0;
	padding: 14px 0 0;
	border-top: 1px solid var(--line-soft);
	color: var(--fg);
	font-size: 15.5px;
	font-weight: 700;
	line-height: 1.4;
}
.model-faq dt:first-of-type { border-top: 0; padding-top: 0; }
.model-faq dd {
	margin: 6px 0 14px;
	color: var(--fg-muted);
	font-size: 15px;
	line-height: 1.6;
}
.model-faq dd:last-child { margin-bottom: 0; }


/* ---------------------------------------------------------------------------
   12  AFFILIATE CTAs

   These exist because the CTAs rendered as bare inline <a>: 17px tall, no
   padding, visually identical to body copy. The links worked, nobody saw them.
   --------------------------------------------------------------------------- */

.cs-cta a,
.cs-cta-video a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 52px;
	padding: 14px 28px;
	border-radius: var(--r-pill);
	background: var(--accent-fill);
	color: var(--accent-ink);
	font-size: 15.5px;
	font-weight: 800;
	line-height: 1.2;
	letter-spacing: .01em;
	text-align: center;
	text-transform: uppercase;
	text-decoration: none;
	box-shadow: 0 6px 20px var(--cta-shadow);
	transition: background-color .15s var(--ease), transform .15s var(--ease);
}
/* `color` here is not redundant. Vendor ships `.no-touch a:hover { color:
   #276fdb }`, and this rule previously set only `background` — so on hover the
   label fell through to the old theme's blue, on an orange button, which is
   both off-brand and barely readable. The resting rule's colour does not carry
   over: a hover rule has to restate every property the vendor hover touches. */
.no-touch .cs-cta a:hover,
.no-touch .cs-cta-video a:hover,
.no-touch .cs-cta a:focus,
.no-touch .cs-cta-video a:focus {
	background: var(--accent-fill-hover);
	color: var(--accent-ink);
}
.cs-cta a:active,
.cs-cta-video a:active { transform: translateY(1px); }

/* Directly under the player — the highest-value position on the page. */
.cs-cta-video {
	margin: 16px 0 4px;
	text-align: center;
}
.cs-cta-video a { width: 100%; box-sizing: border-box; }

.cs-cta { margin: 18px 0; }


/* ---------------------------------------------------------------------------
   12b  CTA GLOW

   An affiliate button earns nothing if it reads as page furniture. A slow
   pulse pulls the eye back to it without moving anything.

   The glow sits on pseudo-elements and only `opacity` animates. Animating
   box-shadow directly — the obvious way, and how the technique is usually
   written — repaints the button on every frame for as long as the tab is
   open. Opacity is composited, so this costs a layer and no repaints.
   Nothing here can shift layout: box-shadow is outside the box model.

   THE RULE THAT MATTERS: a glow pseudo must stay exactly the size of the
   button. `transform: scale()` was the first attempt at making the glow
   breathe, and it produced a black pill behind the button. A non-inset
   box-shadow paints nothing inside its own border-box, so scaling the pseudo
   past 1 pushes that dead zone outside the orange and the page background
   shows through as a dark ring. Scaling below 1 is just as wrong the other
   way: the shadow then paints inward, over the button face and its label.
   Either way the pseudo must sit flush at `inset: 0` with no transform, so
   the unpainted region lands exactly under the opaque button.

   So the breathing comes from cross-fading two glows instead of resizing one.
   ::before is tight and ::after is wide; as the tight one fades out and the
   wide one comes up, the light reads as spreading outward from the button.
   Same effect as the reference's 5px->10px blur animation, no repaint.

   Hover stops it. Once the pointer is on the button the animation has done
   its job, and a target still pulsing under the cursor just reads as noise.

   No reduced-motion rule needed here — the global block in MOTION already
   clamps every infinite animation to a single iteration.
   --------------------------------------------------------------------------- */

.cs-cta a,
.cs-cta-video a { position: relative; }

.cs-cta a::before,
.cs-cta a::after,
.cs-cta-video a::before,
.cs-cta-video a::after {
	content: "";
	position: absolute;
	inset: 0;                /* flush with the button — see the rule above */
	border-radius: inherit;
	pointer-events: none;
}

/* Tight core: strongest at rest, gone at the peak. */
.cs-cta a::before,
.cs-cta-video a::before {
	box-shadow:
		0 0 8px var(--glow),
		0 0 16px var(--glow-soft);
	animation: cta-glow-core 2.2s ease-in-out infinite;
}

/* Wide halo: barely there at rest, dominant at the peak. */
.cs-cta a::after,
.cs-cta-video a::after {
	box-shadow:
		0 0 20px var(--glow),
		0 0 44px var(--glow-soft);
	animation: cta-glow-halo 2.2s ease-in-out infinite;
}

@keyframes cta-glow-core {
	0%, 100% { opacity: .6; }
	50%      { opacity: 0; }
}
@keyframes cta-glow-halo {
	0%, 100% { opacity: .18; }
	50%      { opacity: 1; }
}

/* Settle on the full halo rather than freezing mid-cycle. */
.no-touch .cs-cta a:hover::before,
.no-touch .cs-cta-video a:hover::before {
	animation: none;
	opacity: 0;
}
.no-touch .cs-cta a:hover::after,
.no-touch .cs-cta-video a:hover::after {
	animation: none;
	opacity: 1;
}


/* ---------------------------------------------------------------------------
   13  STUDIO LOGO SLOTS

   The theme sizes these from the grid cell and stretches whatever it finds to
   fill (object-fit defaults to fill), so a 130x30 wordmark rendered at
   236x315 — 1.8x wide, 10.5x tall, and the distortion changed with the
   viewport. Locking the box to 16:9 and using object-fit: contain lets one
   asset work everywhere: a 10.6:1 Brazzers wordmark and a 1:1 BangBros mark
   both sit correctly in the same slot.

   A light plate because most studio wordmarks are near-black and would
   otherwise vanish on this background.
   --------------------------------------------------------------------------- */

.list-sponsors .item .img,
.block-channel .img {
	position: relative;
	width: 100%;
	height: auto;
	padding: 0 0 56.25%;          /* 16:9 fallback */
	aspect-ratio: 16 / 9;
	overflow: hidden;
	box-sizing: border-box;
	/* Was a hard-coded white plate with a #ececec border, from when the studio
	   assets were 130x30 transparent PNGs that needed something light behind
	   them. Every asset is now a composed 1200x675 image — exactly 16:9, with
	   its own background — so it fills this box edge to edge and the plate is
	   never seen. The near-white border was, though: a 1px light outline
	   around every card on a dark page. Both are tokens now, so the fallback
	   sitting behind a slow-loading image matches the theme. */
	background-color: var(--surface-2);
	border: 0;
	/* top corners only — the card clips the bottom two, same as video cards */
	border-radius: var(--r-md) var(--r-md) 0 0;
}

/* the studio page hero is a standalone block, not inside a card, so it keeps
   all four corners */
.block-channel .img {
	border: 1px solid var(--line);
	border-radius: var(--r-md);
}

@supports (aspect-ratio: 16 / 9) {
	.list-sponsors .item .img,
	.block-channel .img { padding: 0; }
}

.list-sponsors .item .img img.thumb,
.block-channel .img img.thumb {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	object-fit: contain;
	object-position: center;
	box-sizing: border-box;
	/* No inset padding on purpose: the artwork is composed at 16:9 with its
	   own margins, so padding here would shrink it twice. */
}

.list-sponsors .item .img .no-thumb,
.block-channel .img .no-thumb {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	/* tokens, not the old light-plate literals — this is the empty-slot state
	   for a studio with no logo, and it has to read in both themes */
	background-color: var(--surface-2);
	color: var(--fg-dim);
	font-size: 13px;
	line-height: 1.2;
	text-align: center;
}

/* Studio page header block

   Was a single stacked column: logo capped at 300px with the description
   underneath, which on a wide screen left the copy as a narrow ribbon beside
   a large empty area, and pushed the affiliate CTA over 1200px down the page.

   Now a two-column hero — logo left, copy and the single CTA right — so the
   click target sits directly under the sentence that sells it. Collapses to
   stacked below 900px. */
.block-channel {
	margin: 0 0 18px;
	padding: 0;
	background: none;
	border: 0;
}

.cs-hero {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: 24px;
}

.cs-hero__media {
	flex: 0 0 340px;
	max-width: 100%;
	margin: 0;
}

.cs-hero__body {
	flex: 1 1 360px;
	min-width: 0;            /* allows wrapping instead of forcing the column wider */
}

/* Comfortable measure. The old block ran ~296px wide; ~70 characters is the
   readable range for body copy. */
.block-channel .desc,
.block-channel .text {
	max-width: 70ch;
	color: var(--fg-muted);
	font-size: 15.5px;
	line-height: 1.7;
}
.block-channel .desc p { margin: 0 0 14px; }
.block-channel .desc p:last-child { margin-bottom: 0; }

.cs-cta__note {
	display: block;
	margin: 8px 0 0;
	color: var(--fg-dim);
	font-size: 12.5px;
}

/* Sections under the hero. These previously ran together as unstyled text
   with no heading hierarchy or spacing. */
.cs-section { margin: 0 0 28px; }

.cs-section > h2 {
	margin: 0 0 12px;
	color: var(--fg);
	font-size: 19px;
	line-height: 1.3;
}

.cs-performers ul,
.cs-performers ol {
	display: flex;
	flex-wrap: wrap;
	gap: 8px 16px;
	margin: 0;
	padding: 0;
	list-style: none;
}
.cs-performers li { margin: 0; }
.cs-performers a { color: var(--fg-muted); }
.no-touch .cs-performers a:hover { color: var(--accent); }

.cs-faq {
	max-width: 80ch;
	color: var(--fg-muted);
	font-size: 15px;
	line-height: 1.7;
}
.cs-faq h2,
.cs-faq h3 {
	margin: 20px 0 6px;
	color: var(--fg);
	font-size: 16px;
	font-weight: 700;
}
.cs-faq p { margin: 0 0 12px; }

@media (max-width: 900px) {
	.cs-hero__media { flex: 1 1 100%; }
	.cs-hero__body  { flex: 1 1 100%; }
}


/* ---------------------------------------------------------------------------
   14  FOOTER
   --------------------------------------------------------------------------- */

/* `.all` and `.footer-margin` are vendor wrappers carrying their own dark
   greys (#212121 / #151515). Invisible against the dark theme, and a slab of
   near-black behind the page in the light one. */
.all,
.footer-margin {
	background: transparent;
}

.footer {
	margin-top: 32px;
	padding: 28px 0 36px;
	/* was hard-coded #08080a, which stayed black in light mode */
	background: var(--surface);
	border-top: 1px solid var(--line);
}

.footer-wrap {
	max-width: 1600px;
	margin: 0 auto;
	padding: 0 var(--gutter);
	box-sizing: border-box;
}

.footer .nav {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 8px;
	margin: 0 0 22px;
	padding: 0;
	list-style: none;
	text-align: left;
}
.footer .nav li {
	float: none;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
}
.footer .nav li a {
	display: block;
	padding: 10px 15px;
	border: 1px solid var(--line);
	border-radius: var(--r-pill);
	background: var(--surface);
	color: var(--fg-muted);
	font-size: 14px;
	font-weight: 500;
	line-height: 1.2;
	text-decoration: none;
	cursor: pointer;
}
.no-touch .footer .nav li a:hover {
	color: var(--fg);
	border-color: var(--fg-dim);
	background: var(--surface-2);
}

.footer .copyright {
	margin: 0 0 14px;
	padding: 0;
	color: var(--fg-muted);
	font-size: 14px;
	line-height: 1.6;
	text-align: left;
	float: none;
	width: auto;
}
.footer .copyright a {
	color: var(--fg);
	font-weight: 700;
	text-decoration: none;
}

.footer .txt {
	margin: 0;
	padding: 16px 0 0;
	border-top: 1px solid var(--line-soft);
	color: var(--fg-dim);
	font-size: 12.5px;
	line-height: 1.65;
	text-align: left;
	float: none;
	width: auto;
}
.footer .txt a { color: var(--fg-muted); }


/* ---------------------------------------------------------------------------
   15  ADVERTISING SLOTS

   Ad creatives are fixed-width and will push the page sideways on a phone if
   left alone. Contain them; never let one set the page width.
   --------------------------------------------------------------------------- */

.content > .top,
.spot,
.footer-margin .content {
	max-width: 100%;
	overflow: hidden;
	text-align: center;
}
.content > .top img,
.spot img,
.block-video .sponsor img,
.block-video .table img {
	max-width: 100%;
	height: auto;
}

.block-video .table {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 10px;
	margin: 18px 0 0;
	width: auto;
	max-width: 100%;
	min-width: 0;
}
.block-video .table .opt {
	display: block;
	float: none;
	width: auto;
	max-width: 100%;
	min-width: 0;
	margin: 0;
}
.block-video .table .opt a { display: block; }
.block-video .sponsor { margin: 12px 0; text-align: center; }

.box.bottom-adv { margin: 18px 0 0; }


/* ---------------------------------------------------------------------------
   16  TABLET AND DESKTOP

   Everything above is the phone layout. From here it only adds.
   --------------------------------------------------------------------------- */

/* --- 480px: two video columns -------------------------------------------- */
@media (min-width: 480px) {
	:root { --gutter: 16px; }

	/* past the point where the search field is fighting for room */
	.site-head .logo img { max-width: 160px; max-height: 36px; }

	.list-videos .margin-fix {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
	.list-models .margin-fix,
	.list-sponsors .margin-fix,
	.list-categories .margin-fix,
	.list-playlists .margin-fix,
	.list-channels .margin-fix {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
	.block-screenshots .margin-fix {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
	.cs-cta-video a { width: auto; min-width: 320px; }
}

/* --- 768px: tablet ------------------------------------------------------- */
@media (min-width: 768px) {
	:root { --gutter: 22px; --head-h: 62px; }

	.headline h1,
	.headline h2 { font-size: 25px; }

	.list-videos .margin-fix {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 28px 16px;
	}
	.list-models .margin-fix,
	.list-sponsors .margin-fix,
	.list-categories .margin-fix,
	.list-playlists .margin-fix,
	.list-channels .margin-fix {
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: 26px 16px;
	}
	.block-screenshots .margin-fix {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	/* the player stops being full-bleed and gets its corners back */
	.block-video .player {
		margin-left: 0;
		margin-right: 0;
		border-radius: var(--r-md);
	}

	.block-model {
		display: grid;
		grid-template-columns: 260px minmax(0, 1fr);
		grid-template-areas:
			"img  facts"
			"desc desc"
			"soc  soc";
		gap: 0 28px;
		align-items: start;
	}
	.block-model .img     { grid-area: img; margin-bottom: 0; max-width: none; }
	.block-model .desc    { grid-area: desc; margin-top: 20px; }
	.model-socials        { grid-area: soc; }
	.block-model .model-list {
		grid-area: facts;
		margin-bottom: 0;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 26px;
	}

	.footer .copyright,
	.footer .txt { font-size: 14px; }
}

/* --- 1024px: desktop shell ----------------------------------------------- */
@media (min-width: 1024px) {
	:root { --gutter: 28px; }
}


/* --- 1200px: the header goes to a single line ----------------------------

   Deliberately NOT 1024. The header carries a logo, a search field, seven nav
   links and the theme toggle; laid out inline that needs roughly 1150px before
   the search field starts being squeezed to nothing. Switching at 1024 put a
   cramped nav on tablets. Below this width the burger and off-canvas drawer
   handle it — which is also what "hamburger on mobile and tablet" means.

   Everything sits on one row: logo, search, nav links, theme toggle. The
   drawer stops being a drawer and becomes a static inline block, and the list
   inside it lays out horizontally.
   -------------------------------------------------------------------------- */
@media (min-width: 1200px) {
	.site-head__bar {
		flex-wrap: nowrap;
		height: auto;
		padding: 10px var(--gutter);
		row-gap: 0;
		column-gap: 18px;
	}

	/* Scoped through .site-head on purpose. The base rule is
	   `.site-head .site-head__menu { display: flex }` (0,2,0); a bare
	   `.site-head__menu { display: none }` here is (0,1,0) and loses to it, so
	   the burger rendered at every width — including desktop, where the drawer
	   is static and there is nothing for it to slide open. That was the bug. */
	.site-head .site-head__menu,
	.site-head .site-drawer__head,
	.site-head .site-drawer__scrim { display: none; }

	.site-head .logo img { max-width: 170px; max-height: 40px; }

	/* Inline, not a second row. `margin-left: auto` pushes the nav to the right
	   of the search field, which is what puts the whole thing on one line. */
	.site-head__bar > .site-head__nav {
		flex: 0 1 auto;
		order: 2;
		min-width: 0;
		margin-left: auto;
	}
	.site-head__bar > .theme-toggle { order: 3; }
	.site-head .navigation { display: block; width: auto; }

	.site-drawer {
		position: static;
		display: block;
		width: auto;
		max-width: none;
		transform: none;
		visibility: visible;
		overflow: visible;
		background: none;
		border: 0;
		box-shadow: none;
		padding: 0;
	}

	.site-head .search {
		flex: 1 1 260px;
		padding: 0;
		max-width: 420px;
		min-width: 180px;
	}
	#search_form .search-text input { height: 42px; }
	.site-head .search-button { height: 42px; }

	.site-head .member-links {
		flex: 0 0 auto;
		margin: 0;
		padding: 0;
		border: 0;
		position: relative;
	}
	.site-head .member-links > ul { gap: 10px; padding: 0; flex-wrap: nowrap; }
	.site-head .member-links > ul > li > a { padding: 9px 18px; }
	.site-head .member-links .languages > ul {
		position: absolute;
		right: 0;
		top: 100%;
		z-index: 20;
		flex-direction: column;
		flex-wrap: nowrap;
		min-width: 170px;
		margin-top: 8px;
		padding: 6px;
		background: var(--surface-2);
		border: 1px solid var(--line);
		border-radius: var(--r-md);
		box-shadow: 0 12px 30px var(--shadow);
		visibility: hidden;
		opacity: 0;
		transition: opacity .15s var(--ease), visibility .15s var(--ease);
	}
	.site-head .member-links .languages:hover > ul { visibility: visible; opacity: 1; }

	/* Inline nav. nowrap keeps it on the header's line — allowed to wrap it
	   would drop items onto a second row and reintroduce the two-row header
	   this replaces. The row is sized so seven items fit at 1200px. */
	.site-head .primary {
		display: flex;
		flex-direction: row;
		flex-wrap: nowrap;
		align-items: center;
		gap: 0;
		margin: 0;
		padding: 0;
		border-top: 0;
	}
	.site-head .primary > li { position: relative; flex: 0 0 auto; }
	.site-head .primary > li > a {
		padding: 10px 11px;
		border-radius: var(--r-sm);
		font-size: 13.5px;
		font-weight: 700;
		text-transform: uppercase;
		letter-spacing: .02em;
		white-space: nowrap;
		border-bottom: 0;
	}
	.no-touch .site-head .primary > li > a:hover { background: var(--surface-2); color: var(--accent); }
	.site-head .navigation .primary > li.selected > a {
		background: var(--accent-fill);
		color: var(--accent-ink);
		border: 0;
	}
	/* upload dropdown behaves like a dropdown again */
	.site-head .primary > li > ul {
		position: absolute;
		top: 100%;
		left: 0;
		z-index: 20;
		min-width: 190px;
		margin: 0;
		padding: 6px;
		background: var(--surface-2);
		border: 1px solid var(--line);
		border-radius: var(--r-md);
		box-shadow: 0 12px 30px var(--shadow);
		visibility: hidden;
		opacity: 0;
		transition: opacity .15s var(--ease), visibility .15s var(--ease);
	}
	.site-head .primary > li:hover > ul { visibility: visible; opacity: 1; }
	.site-head .primary > li > ul > li > a { border-radius: var(--r-sm); }

	.site-head .secondary { display: flex; padding: 0; }
}


/* --- 1024px: body layout -------------------------------------------------
   Kept on its own breakpoint. The two-column body works from 1024, but the
   inline header needs 1200 — tying them together forced one of the two to be
   wrong on tablets.
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
	/* Two-column body: content beside a sidebar — WHEN there is one.

	   This is flex rather than grid on purpose. The sidebar is optional:
	   `enable_sidebar` is false in production and true in the local mirror, so
	   the same CSS has to lay out with and without it. A grid with a declared
	   `minmax(0,1fr) 264px` reserves the second track whether or not anything
	   fills it, which left ~290px of dead space down the right of every
	   desktop page on production. Flex just gives the space back. */
	.main-content {
		display: flex;
		flex-direction: row;
		flex-wrap: wrap;
		align-items: flex-start;
		gap: 0 26px;
	}
	/* Vendor builds this column with three cooperating hacks, because in its
	   layout the sidebar is a float in the same flow:
	     .sidebar + .main-container            { width: calc(100% - 265px) }
	     .sidebar + .main-container .headline  { margin-left: -265px }
	     .sidebar + .main-container .item      { width: calc(25% - 10px) }
	   The flex row here already allots the sidebar its own track, so all three
	   are applied on top of a layout that has allowed for them once already:
	   the column lost 265px, the headings hung 265px off the left edge of the
	   page, and the cards were sized to a quarter of the wrong width. Each
	   override below has to out-specify the vendor selector it cancels.

	   All three are scoped `.sidebar + .main-container`, so when the sidebar is
	   switched off they stop matching on their own and these overrides become
	   inert — which is the behaviour we want. */
	.main-container {
		order: 1;
		flex: 1 1 0;
		min-width: 0;
	}
	.main-content .sidebar + .main-container { width: auto; }

	.main-content .sidebar + .main-container > .headline:first-child,
	.main-content .sidebar + .main-container div:first-child .headline,
	.main-content .sidebar + .main-container .headline {
		margin-left: 0;
		width: auto;
	}

	.main-content .sidebar + .main-container .list-videos .item,
	.main-content .sidebar + .main-container .list-playlists .item,
	.main-content .sidebar + .main-container .list-models .item,
	.main-content .sidebar + .main-container .list-sponsors .item {
		width: auto;
		margin: 0;
	}
	.sidebar {
		order: 2;
		flex: 0 0 264px;
		margin: 0;
		padding: 20px;
		background: var(--surface);
		border: 1px solid var(--line);
		border-radius: var(--r-lg);
		position: sticky;
		top: calc(var(--head-h) + 88px);
	}
	.sidebar .headline { padding-top: 0; margin-bottom: 12px; }
	.sidebar .headline + .list { margin-bottom: 20px; }
	.sidebar .list { flex-direction: column; gap: 2px; }
	.sidebar .list li a {
		width: 100%;
		box-sizing: border-box;
		justify-content: space-between;
		padding: 9px 12px;
		border: 0;
		border-radius: var(--r-sm);
		background: none;
	}
	.no-touch .sidebar .list li a:hover { background: var(--surface-2); }

	.list-videos .margin-fix { grid-template-columns: repeat(3, minmax(0, 1fr)); }

	.footer .nav { justify-content: center; }
	.footer .copyright,
	.footer .txt { text-align: center; }
	.footer .txt { max-width: 900px; margin: 0 auto; }
}

/* --- 1280px: four video columns ------------------------------------------ */
@media (min-width: 1280px) {
	.list-videos .margin-fix { grid-template-columns: repeat(4, minmax(0, 1fr)); }
	.list-models .margin-fix,
	.list-sponsors .margin-fix,
	.list-categories .margin-fix,
	.list-playlists .margin-fix,
	.list-channels .margin-fix { grid-template-columns: repeat(5, minmax(0, 1fr)); }

	.headline h1,
	.headline h2 { font-size: 27px; }
}

/* --- 1600px --------------------------------------------------------------- */
@media (min-width: 1600px) {
	.list-videos .margin-fix { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}


/* ---------------------------------------------------------------------------
   MOTION

   Respect the OS setting. Everything above degrades to an instant state
   change; nothing depends on a transition to become usable.
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ---------------------------------------------------------------------------
   FAQ ACCORDION

   The markup moved from <dl> to <details>/<summary> and the old dt/dd rules
   stopped matching, which left the questions rendering at the browser default
   and unreadable on a phone. These replace them.

   Mobile first, and that is not a slogan here — 90% of this site's traffic is
   phones. Sizes are set for a 6-inch screen and only grow at the breakpoint.

     16px question text   below this iOS Safari zooms on tap
     15px answer text     the smallest that stays comfortable at arm's length
     48px minimum row     above the 44px tap-target floor, with room for a miss
   --------------------------------------------------------------------------- */

.model-faq__item {
	border-top: 1px solid var(--line-soft);
}
.model-faq__item:first-of-type {
	border-top: 0;
}

.model-faq__item > summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 14px;
	min-height: 48px;
	padding: 13px 0;
	cursor: pointer;
	font-size: 16px;
	font-weight: 650;
	line-height: 1.4;
	color: var(--fg);
	/* The default disclosure triangle is tiny, sits on the wrong side and
	   cannot be styled consistently across browsers. Replaced below. */
	list-style: none;
	-webkit-tap-highlight-color: transparent;
}
.model-faq__item > summary::-webkit-details-marker { display: none; }

/* The affordance. A plus that becomes a minus, right-aligned, because a
   question with no visible control reads as a heading and nobody taps it. */
.model-faq__item > summary::after {
	content: "";
	flex: 0 0 22px;
	height: 22px;
	background:
		linear-gradient(var(--fg-muted), var(--fg-muted)) center/11px 2px no-repeat,
		linear-gradient(var(--fg-muted), var(--fg-muted)) center/2px 11px no-repeat;
	transition: transform .18s ease, background-size .18s ease;
}
.model-faq__item[open] > summary::after {
	/* vertical bar collapses, leaving a minus */
	background:
		linear-gradient(var(--accent, var(--fg)), var(--accent, var(--fg))) center/11px 2px no-repeat;
	transform: rotate(180deg);
}
.model-faq__item[open] > summary {
	color: var(--accent, var(--fg));
}

.model-faq__item > summary:hover { color: var(--accent, var(--fg)); }
.model-faq__item > summary:focus-visible {
	outline: 2px solid var(--accent, var(--fg));
	outline-offset: 3px;
	border-radius: 4px;
}

.model-faq__a {
	padding: 0 34px 16px 0;   /* right padding clears the icon column */
	font-size: 15px;
	line-height: 1.65;
	color: var(--fg-muted);
}

/* Desktop gets a little more air. Everything above already works without it. */
@media (min-width: 768px) {
	.model-faq__item > summary { font-size: 17px; padding: 15px 0; }
	.model-faq__a { font-size: 16px; padding-bottom: 18px; }
}

/* Respect the setting rather than animating regardless. */
@media (prefers-reduced-motion: reduce) {
	.model-faq__item > summary::after { transition: none; }
}

/* ===========================================================================
   Performer pages — measured fixes, 2026-08-15
   Applied to the shared stylesheet rather than to a page: PERFORMER-TEMPLATE.md
   forbids building a performer by hand, and Cory Chase is the reason it says so.
   These land on every performer at once.
   =========================================================================== */

/* 1. The portrait was being upscaled.
      Source is 176x224 — and both of KVS's "sizes" are the same file, byte for
      byte (identical md5). It rendered at 260x347, which on a 2x phone asks for
      520px of detail from a 176px image: a third of what it needs, on the first
      thing anyone sees. Capping the width keeps the stretch small enough to
      stop reading as soft.

      This is a patch, not the fix. Re-fetch portraits at 520px or wider and put
      this cap straight back up to 260px. */
.block-model .img { max-width: 200px; }
@media (min-width: 768px) { .block-model .img { max-width: 220px; } }

/* 2. The follower count carried exactly the same weight as the handle.
      Both were 14px / 600 in the same colour, so "@JohnnySins" and "1M" read as
      one token — a secondary metric competing with the identity it belongs to.
      Now quieter, and tabular so the digits line up down the column. */
.model-chip__count {
	font-size: 12.5px;
	font-weight: 500;
	color: rgba(245, 245, 247, 0.58);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.01em;
}

/* 3. A section heading was smaller than the text it introduced.
      "<name> profiles and links" rendered at 11.5px against 14.5px body copy —
      the hierarchy was upside down. */
.block-model h3 {
	font-size: 15px;
	font-weight: 600;
	letter-spacing: -0.01em;
	margin: 0 0 10px;
}

/* 4. The chips are the main thing a thumb aims at on this page and they gave no
      press response. A 1px push is enough to register as a hit. */
.model-chip { transition: transform 0.12s ease, background-color 0.12s ease; }
.model-chip:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) {
	.model-chip { transition: none; }
	.model-chip:active { transform: none; }
}

/* ===========================================================================
   Performer FAQ — third pass, 2026-08-15. Line-separated rows, two columns.

   Pass two put each question on its own padded card with a 52px ring. It read
   well and it was far too tall: nine cards ran 1,164px on desktop and about
   830px on a phone, for a block that is the last thing on the page. Ten
   questions of that treatment is a scroll nobody finishes.

   The reference solves it by removing the card entirely. A question is a row,
   a 1px line separates it from the next, and the affordance shrinks to a
   chevron. Two columns above 900px halve the height again.

   Height is the whole point of this pass:
       desktop   1,164px -> ~470px
       phone     ~830px  -> ~500px

   Kept: native <details>, no JavaScript, answers in raw HTML. The gradient
   stays because it is the part of the port that worked.
   =========================================================================== */

.model-faq {
	position: relative;
	padding: 22px 20px 6px;
	margin-top: 26px;
	border-radius: 20px;
	background:
		radial-gradient(ellipse 55% 120% at 10% 0%, rgba(255, 214, 90, 0.18), transparent 60%),
		radial-gradient(ellipse 60% 90% at 94% 6%, rgba(255, 255, 255, 0.045), transparent 58%),
		#08080a;
	box-shadow: inset 0 0 0 1px var(--line-soft);
	overflow: hidden;
}

.model-faq > h2 { margin: 0 0 6px; }

/* The grid is gated on :has() because not every performer page has been
   regenerated onto the <details> markup — gina-valentina on dev, and every
   page on kvs, still emit a single <dl>. One <dl> in a two-column grid is one
   filled column and one empty one. Browsers without :has() land on the same
   single-column fallback, which is correct rather than merely safe. */
.model-faq:has(.model-faq__item) {
	display: grid;
	grid-template-columns: 1fr;
	column-gap: 56px;
	row-gap: 0;
}
/* The heading spans both columns, so it stays a heading and not a first row. */
.model-faq:has(.model-faq__item) > h2 { grid-column: 1 / -1; }

/* Two columns once there is room for a 38-character question at 16px without
   wrapping every row. 900px, not 768px: portrait tablets are 810px wide and
   would get two cramped columns for no gain. */
@media (min-width: 900px) {
	.model-faq:has(.model-faq__item) {
		grid-template-columns: 1fr 1fr;
		padding: 26px 28px 10px;
	}
	.model-faq:has(.model-faq__item) > h2 { margin-bottom: 10px; }
}

/* The row. Grid items stretch by default, which is what keeps the separator
   lines level across a pair when one side is open and the other is not. */
.model-faq__item {
	margin: 0;
	padding: 0;
	border-radius: 0;
	border-top: 0;
	border-bottom: 1px solid var(--line-soft);
	background: none;
	box-shadow: none;
	transition: none;
}

.model-faq__item > summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	min-height: 52px;
	padding: 15px 2px;
	font-size: 16px;
	font-weight: 600;
	line-height: 1.35;
	color: var(--fg);
	list-style: none;
}
.model-faq__item > summary::-webkit-details-marker { display: none; }

/* Open keeps the plain foreground. Nine accent-coloured headings in a column
   made the accent ordinary; it now appears once, on the chevron you pressed. */
.model-faq__item[open] > summary { color: var(--fg); }

/* Pass two's ring is off. The markup is generated and not ours to edit, so the
   icon has to be a pseudo-element either way — this one is just much smaller. */
.model-faq__item > summary::before { content: none; }

/* Chevron. Two borders on a rotated square, so it stays crisp at any DPI and
   costs no request. background:none is not decorative — it cancels the
   plus/minus gradients the base rule paints on this same pseudo-element. */
.model-faq__item > summary::after {
	content: "";
	flex: 0 0 auto;
	width: 9px;
	height: 9px;
	margin-right: 5px;
	background: none;
	border: 0;
	border-right: 1.6px solid var(--fg-muted);
	border-bottom: 1.6px solid var(--fg-muted);
	transform: translateY(-3px) rotate(45deg);
	transition: transform 0.3s cubic-bezier(0.22, 0.68, 0, 1), border-color 0.2s ease;
}
.model-faq__item[open] > summary::after {
	background: none;
	border-right-color: var(--accent);
	border-bottom-color: var(--accent);
	transform: translateY(2px) rotate(225deg);
}

.model-faq__item > summary:hover::after {
	border-right-color: var(--fg);
	border-bottom-color: var(--fg);
}

/* The answer clears the chevron column on the right and lines up with the
   question on the left. */
.model-faq__a {
	padding: 0 30px 18px 2px;
	font-size: 15px;
	line-height: 1.7;
	color: var(--fg-muted);
}

@media (min-width: 900px) {
	.model-faq__item > summary { font-size: 16.5px; padding: 16px 2px; }
	.model-faq__a { font-size: 15.5px; padding-bottom: 20px; }
}

/* Phones. The row is the tap target at 52px, comfortably over the 44px floor,
   so the chevron is free to be small. 16px on the question is the iOS Safari
   zoom threshold and does not go lower. */
@media (max-width: 640px) {
	.model-faq {
		padding: 18px 14px 4px;
		border-radius: 16px;
		margin-top: 20px;
	}
	.model-faq__item > summary { padding: 14px 0; gap: 12px; }
	.model-faq__item > summary::after { margin-right: 2px; }
	.model-faq__a { padding: 0 24px 16px 0; }
}

@media (prefers-reduced-motion: reduce) {
	.model-faq__item > summary::after { transition: none; }
}

/* ===========================================================================
   Performer hero — portrait with an overlapping profile card, 2026-08-16.

   Ported from a React testimonial carousel. The carousel itself is gone: it
   cycles three people, and a performer page has one. What was worth taking is
   the composition — a portrait, a dark card riding over its edge, a bold name
   over a muted identity line, and the links as a row of round-badged pills.

   No JavaScript, no new content. The H1 moved into the card, four fact rows
   moved from the list into the meta line, and the socials block moved out from
   under the portrait. Every value was already on the page.

   PORTRAIT SIZE IS THE CONSTRAINT. The masters are 300x400 (screenshot1) and
   225x300 (screenshot2). A reference-sized 470px photo would be a 0.3x upscale
   of a face, so the portrait stays at 200/240px, where a 300px master is still
   0.75x on a 2x screen. Re-fetch portraits at 600px+ and these two numbers are
   the only ones to raise.
   =========================================================================== */

.model-hero {
	position: relative;
	margin: 0 0 22px;
}

/* The portrait. Sized to what the source can carry, not to the layout. */
.block-model .img {
	max-width: 200px;
	margin: 0 0 0 4px;
	border-radius: 20px;
	box-shadow: inset 0 0 0 1px var(--line-soft);
}

/* The card. Rides up over the portrait's lower edge, which is the whole trick
   in the reference — the two planes read as stacked rather than adjacent. */
.model-card {
	position: relative;
	z-index: 1;
	margin: -40px 0 0;
	padding: 22px 18px 20px;
	border-radius: 22px;
	background:
		radial-gradient(ellipse 70% 100% at 8% 0%, rgba(255, 214, 90, 0.22), transparent 58%),
		#111114;
	box-shadow:
		inset 0 0 0 1px var(--line-soft),
		0 18px 40px -18px rgba(0, 0, 0, 0.85);
}

.model-card > h1 {
	margin: 0 0 8px;
	font-size: 27px;
	font-weight: 700;
	line-height: 1.15;
	letter-spacing: -0.02em;
	color: var(--fg);
}

/* The identity line. Separators are drawn between spans rather than written
   into the template, so a performer missing a height gets no orphaned dot. */
.model-card__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0 8px;
	margin: 0 0 20px;
	font-size: 13.5px;
	font-weight: 500;
	line-height: 1.6;
	color: var(--fg-muted);
}
/* The separator trails its own item rather than leading the next one. As a
   ::before on the following span it became the first thing on a wrapped line —
   a line starting "· Active Since 2006". Trailing, a wrap leaves the dot at the
   end of the line above, where it reads as a continuation. */
.model-card__meta span:not(:last-child)::after {
	content: "·";
	margin-left: 8px;
	color: var(--fg-dim);
}

/* --- the links -------------------------------------------------------------
   The reference uses bare circular icons. Ours keep the handle and the
   follower count, because on a profile page those are the content: they are
   what shows the page knows which account is really theirs. The circle became
   a badge on the pill instead of replacing it. */

.model-card .model-socials { margin: 0; }

.model-card .model-socials h3 {
	margin: 0 0 12px;
	font-size: 11px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--fg-dim);
}

.model-card .model-socials ul { gap: 9px; }

/* Targeted at `.model-socials a`, not at `.model-chip`. Two generations of
   this block are live: the newer one wraps each link in
   `model-chip model-chip--<platform>` with a handle and a follower count, the
   older one is a bare <ul><li><a> with no classes at all. Every kvs performer
   and some dev ones are still on the older shape, and a .model-chip selector
   styled none of them. The <a> inside .model-socials is what both have. */
.model-card .model-socials a {
	gap: 10px;
	min-height: 46px;
	padding: 5px 15px 5px 5px;
	border: 0;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.045);
	box-shadow: inset 0 0 0 1px var(--line-soft);
	font-size: 13.5px;
}

/* The badge. The icons are fill="currentColor", so the dark glyph is a colour
   change, not a second copy of every SVG. */
.model-card .model-socials a svg {
	box-sizing: border-box;
	width: 32px;
	height: 32px;
	padding: 7px;
	border-radius: 50%;
	background: #f2f2f4;
	color: #0b0b0d;
}
/* The older markup puts fill on the <path>, where `color` cannot reach it. */
.model-card .model-socials a svg path[fill="currentColor"] { fill: currentColor; }

.model-card .model-chip__label {
	max-width: 190px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.no-touch .model-card .model-socials a:hover {
	background: rgba(255, 255, 255, 0.08);
	box-shadow: inset 0 0 0 1px var(--line);
	color: var(--fg);
}
.no-touch .model-card .model-socials a:hover svg { background: #fff; }

.model-card .model-socials-note {
	margin: 14px 0 0;
	font-size: 12px;
	line-height: 1.5;
	color: var(--fg-dim);
}

/* --- the rest of the block -------------------------------------------------
   .block-model was a grid with img/facts/desc/soc areas. Its children are now
   .model-hero, .model-list and .desc in a single column, so the grid is off
   and the areas with it. */
.block-model {
	display: block;
}
.block-model .model-list { margin-top: 0; }
.block-model .desc { margin-top: 22px; }

/* --- 768px and up ----------------------------------------------------------
   Portrait and card side by side, card overlapping from the right and
   vertically centred against the photo, as in the reference. */
@media (min-width: 768px) {
	.block-model { display: block; }

	.model-hero {
		display: flex;
		align-items: center;
		margin-bottom: 26px;
	}

	.block-model .img {
		flex: 0 0 auto;
		width: 240px;
		max-width: 240px;
		margin: 0;
		border-radius: 24px;
	}

	.model-card {
		flex: 1 1 auto;
		min-width: 0;
		margin: 0 0 0 -56px;
		padding: 30px 32px 28px;
		border-radius: 26px;
		box-shadow:
			inset 0 0 0 1px var(--line-soft),
			0 26px 60px -24px rgba(0, 0, 0, 0.9);
	}

	.model-card > h1 { font-size: 34px; margin-bottom: 10px; }
	.model-card__meta { font-size: 14.5px; margin-bottom: 24px; }
	.model-card .model-socials a { font-size: 14px; }

	.block-model .model-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 28px;
		margin-top: 0;
	}
	.block-model .desc { margin-top: 24px; }
}

/* Below 360px the card's own padding plus the page gutter leaves too little
   for a pill with a long handle. */
@media (max-width: 359px) {
	.model-card { padding: 20px 14px 18px; }
	.model-card .model-chip__label { max-width: 130px; }
}

/* A performer with no photo now drops the portrait slot entirely and the card
   stands on its own. The old layout kept a shrunken placeholder so the grid
   would not reflow; in this one it left a small grey rectangle floating above
   the card with a negative margin pulling the card halfway over it, which read
   as a bug rather than as a missing image. */
.model-hero:has(.no-thumb) .img { display: none; }
.model-hero:has(.no-thumb) .model-card { margin-top: 0; margin-left: 0; }

/* ===========================================================================
   HEADER — rebuilt, treatment adapted from pinkclips.mobi, 2026-08-16.

   The old bar put logo, search, theme toggle and burger on one row at every
   width and let the search field absorb the difference. At 375px that left the
   field about 120px wide and the logo capped at 34vw, so both were squeezed and
   neither looked deliberate.

   The reference solves it by not carrying search in the bar on a phone at all:
   burger left, logo centred, search as an icon. Tapping search takes over the
   row — field and a close X, nothing else. The bar height never changes, so
   nothing below it moves.

   Above 768px the field comes back into the row and the bar becomes what the
   reference shows on desktop: a larger logo, a plain pill field with the
   magnifier as an accent glyph rather than a filled block, and nav items that
   carry an icon beside the label.
   =========================================================================== */

.site-head__bar {
	gap: 10px;
	padding: 0 12px;
}

/* --- logo ------------------------------------------------------------------
   The lockup is 3.42:1 (viewBox 9383x2741), wider than the 4.31:1 wordmark it
   replaces, so it is sized by HEIGHT and left to find its own width. The vw-based
   max-width is what made it shrink on small phones; with the field out of the
   row there is nothing left to compete with.

   height is DECLARED, not max-height with height:auto. These SVGs carry a
   viewBox and no width/height attributes, so they have a ratio but no intrinsic
   size. Inside a shrink-to-fit box — which is what .logo becomes once it is
   absolutely positioned on phones — `width: auto` on such an image resolves
   against a container that is itself sizing to the image. That circularity
   settles at zero and the logo disappears entirely. A declared height breaks
   the loop and the ratio supplies the width. */
.site-head .logo img {
	max-width: none;
	max-height: none;
	width: auto;
	height: 32px;
}

/* --- the two icon buttons in the bar --------------------------------------
   .search-toggle deliberately sits OUTSIDE .navigation. The vendor binds
   `$(".navigation button").on("click", ...)` to toggle the drawer, so a button
   placed inside it would slide the menu open every time search was tapped. */
.site-head .search-toggle {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 42px;
	height: 42px;
	padding: 0;
	border: 0;
	border-radius: var(--r-md);
	background: none;
	color: var(--fg);
	cursor: pointer;
}
.no-touch .site-head .search-toggle:hover { background: var(--surface-2); color: var(--accent); }
.site-head .search-toggle:active { background: var(--surface-3); }
.site-head .search-toggle__close { display: none; }

/* --- phones ---------------------------------------------------------------- */
@media (max-width: 767px) {
	/* The logo is centred against the BAR, not against what is left over after
	   the buttons. One button on the left and two on the right would otherwise
	   push it 21px off centre, which is visible at this size.

	   position:relative is safe here even though the drawer is a fixed-position
	   descendant: only transform, filter and containment create a containing
	   block for fixed elements. That was the trap with backdrop-filter. */
	.site-head__bar {
		position: relative;
		justify-content: space-between;
	}

	.site-head .logo {
		position: absolute;
		left: 50%;
		top: 50%;
		transform: translate(-50%, -50%);
		margin: 0;
	}
	.site-head .logo img { height: 30px; }

	/* Order within the row: burger, then the two icons on the right. The logo is
	   out of flow, so it takes no part in this. */
	.site-head__bar > .site-head__nav   { order: 0; }
	.site-head__bar > .search-toggle    { order: 1; margin-left: auto; }
	.site-head__bar > .theme-toggle     { order: 2; }

	/* The field is in the DOM at every width — it is a real <form> a crawler and
	   a keyboard user can reach — it just does not occupy the row until asked. */
	.site-head .search { display: none; }

	.site-head.search-open .search {
		display: block;
		flex: 1 1 auto;
		min-width: 0;
	}
	.site-head.search-open .logo,
	.site-head.search-open .site-head__nav,
	.site-head.search-open .theme-toggle { display: none; }

	.site-head.search-open .search-toggle__find  { display: none; }
	.site-head.search-open .search-toggle__close { display: block; }
	.site-head.search-open .search-toggle { order: 2; }
}

/* --- the field -------------------------------------------------------------
   The reference's field is a plain pill: one flat fill, no outline, and the
   magnifier drawn in the accent rather than sitting on a filled accent block.
   The block read as a submit button competing with the field it belonged to. */
.site-head .search form {
	background: var(--surface-2);
	border: 0;
	box-shadow: inset 0 0 0 1px var(--line-soft);
	border-radius: 999px;
	padding-right: 4px;
	transition: box-shadow .15s var(--ease);
}
.site-head .search form:focus-within {
	box-shadow: inset 0 0 0 1px var(--accent);
}
#search_form .search-text input { padding-left: 18px; }

.site-head .search-button {
	width: 40px;
	height: 40px;
	background: none;
	color: var(--accent);
	border-radius: 50%;
}
.no-touch .site-head .search-button:hover { background: var(--accent-fill-hover); }

/* --- nav icons -------------------------------------------------------------
   Drawn as masks off the ids the vendor already emits (item1..item10), so the
   markup stays untouched — those ten <li> blocks are wrapped in feature flags
   and editing each one to add an <svg> is ten chances to break a conditional.

   background-color: currentColor means each icon inherits the link's colour,
   including the accent on hover and on the selected item, with one declaration
   instead of a fill per state.

   Scoped through .navigation, at (0,3,1), because that is what the existing
   rules use and they have to be beaten: the vendor hangs a 3px animated
   underline off this same ::before, and the header CSS answers it with
   `display: none`. The underline was already switched off, so the pseudo-element
   is free — it just has to be switched back on and un-absolute-positioned. */
.site-head .navigation .primary > li > a {
	display: flex;
	align-items: center;
	gap: 10px;
}
.site-head .navigation .primary > li > a::before {
	display: block;
	position: static;
	content: "";
	flex: 0 0 auto;
	width: var(--nav-ico-size, 19px);
	height: var(--nav-ico-size, 19px);
	/* All four cancel a vendor declaration: it ships left/bottom, a 3px height,
	   a zero width it animates to 100% on hover, and a hardcoded blue. */
	left: auto;
	bottom: auto;
	background-color: currentColor;
	transition: none;
	-webkit-mask: var(--nav-ico) center / contain no-repeat;
	mask: var(--nav-ico) center / contain no-repeat;
}

/* The hover state has to restate the width, and this is the whole reason the
   size is a custom property rather than a literal.

   The vendor's underline animation is `width: 0` growing to `width: 100%` on
   hover, and it lives on this same ::before. Pinning the width only in the rest
   state left the hover rule live: pointing at a link stretched its icon mask to
   the full width of the link, which pushed the label out of the flex row and
   straight over the neighbouring item. Every hover produced two labels on top
   of each other.

   `.highlight.drop` gets its own vendor override at `width: auto` — on a masked
   box with no content that computes to 0, so it needs answering too. */
.no-touch .site-head .navigation .primary > li > a:hover::before,
.no-touch .site-head .navigation .primary > li.highlight.drop > a:hover::before {
	width: var(--nav-ico-size, 19px);
}

/* An item with no icon assigned gets no empty 19px gap. */
.site-head .navigation .primary > li > a:not([id])::before,
.site-head .navigation .primary > li > ul a::before { display: none; }

.site-head #item1  { --nav-ico: 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%3Cpath d='M3 10.5 12 3l9 7.5'/%3E%3Cpath d='M5.5 9.5V20h13V9.5'/%3E%3Cpath d='M9.5 20v-6h5v6'/%3E%3C/svg%3E"); }
.site-head #item2  { --nav-ico: 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%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 6.5V12l3.5 2.5'/%3E%3C/svg%3E"); }
.site-head #item3  { --nav-ico: 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%3Cpath d='m12 3.5 2.6 5.4 5.9.8-4.3 4.1 1 5.9-5.2-2.8-5.2 2.8 1-5.9L3.5 9.7l5.9-.8z'/%3E%3C/svg%3E"); }
.site-head #item4  { --nav-ico: 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%3Cpath d='M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); }
.site-head #item5  { --nav-ico: 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='7' y='3.5' width='13.5' height='13.5' rx='2.5'/%3E%3Cpath d='M17 20.5H6a2.5 2.5 0 0 1-2.5-2.5V7'/%3E%3C/svg%3E"); }
.site-head #item6  { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Crect x='3' y='3' width='8' height='8' rx='2.4'/%3E%3Crect x='13' y='3' width='8' height='8' rx='2.4'/%3E%3Crect x='3' y='13' width='8' height='8' rx='2.4'/%3E%3Crect x='13' y='13' width='8' height='8' rx='2.4'/%3E%3C/svg%3E"); }
.site-head #item7  { --nav-ico: 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='2.5' y='5' width='19' height='14' rx='2.5'/%3E%3Cpath d='M7 5v14M17 5v14M2.5 12h19'/%3E%3C/svg%3E"); }
.site-head #item8  { --nav-ico: 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%3Ccircle cx='12' cy='8' r='4'/%3E%3Cpath d='M4.5 20.5a7.5 7.5 0 0 1 15 0'/%3E%3C/svg%3E"); }
.site-head #item9  { --nav-ico: 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%3Cpath d='M4 6.5h11M4 12h11M4 17.5h7'/%3E%3Cpath d='m17 12 4 2.75L17 17.5z'/%3E%3C/svg%3E"); }
.site-head #item10 { --nav-ico: 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='2.5' y='7.5' width='19' height='13' rx='2.5'/%3E%3Cpath d='m8 3.5 4 4 4-4'/%3E%3C/svg%3E"); }

/* --- 768px and up ---------------------------------------------------------- */
@media (min-width: 768px) {
	.site-head .logo img { height: 34px; }
	.site-head .search-toggle { display: none; }
	.site-head .search { display: block; }
	/* Vertical padding restored deliberately. From 1024 the bar is height:auto
	   and takes its height from `padding: 10px var(--gutter)` plus its tallest
	   child, so a shorthand of `0 16px` collapses it onto the logo — a 44px logo
	   in a 44px bar, touching both edges. */
	.site-head__bar { gap: 14px; padding: 10px 16px; }

	/* Exactly one item in the row is allowed to give, and it is the field.
	   Both were shrinkable before: flexbox then split the deficit between them,
	   so the nav was handed 726px for 819px of links and clipped "Porn Stars"
	   off the right edge while the field still sat at 390px. The nav is now
	   rigid and the field takes whatever is left, between a 180px floor and a
	   cap — so the row either fits or the field gets narrow, and nothing is
	   ever cut off. */
	.site-head__bar > .site-head__nav { flex: 0 0 auto; min-width: auto; }
	.site-head .search {
		flex: 1 1 0;
		min-width: 180px;
		max-width: 440px;
	}
}

/* --- the desktop row ------------------------------------------------------- */
@media (min-width: 1200px) {
	.site-head__bar { gap: 18px; padding: 14px 24px; }
	.site-head .logo img { max-width: none; height: 42px; }

	/* The reference gives the field real width — it is the second thing in the
	   bar and reads as a destination, not as a leftover. It is the only item
	   allowed to shrink, so it also absorbs whatever the nav needs. */
	.site-head .search { max-width: 420px; }

	/* Sentence case, not uppercase. With an icon beside it an uppercase label
	   reads as a second graphic rather than as a word. */
	.site-head .navigation .primary > li > a {
		padding: 9px 11px;
		font-size: 14px;
		font-weight: 600;
		text-transform: none;
		letter-spacing: 0;
	}
}

/* Icons cost ~29px per item and there are seven items, so they need about
   200px of row that below 1400px does not exist: at 1200 the arithmetic leaves
   the search field at its 180px floor, which is a worse trade than going
   without. Measured on this nav — recheck if items are added or removed.

   Below 1400 the label carries the item on its own, which is what the header
   did before and it fit. The drawer keeps its icons at every width: it is a
   column, so it has the room. */
@media (min-width: 768px) and (max-width: 1399px) {
	.site-head .navigation .primary > li > a::before { display: none; }
	.site-head .navigation .primary > li > a { gap: 0; }
}

@media (min-width: 1400px) {
	.site-head__bar { gap: 20px; padding: 15px 28px; }
	.site-head .logo img { height: 44px; }
	.site-head .search { max-width: 440px; }
	.site-head .navigation .primary > li > a {
		padding: 9px 12px;
		font-size: 14.5px;
		gap: 9px;
		/* Set on the link, not on ::before, so the rest state and the hover
		   state read the same value and cannot drift apart. */
		--nav-ico-size: 20px;
	}
}

/* ===========================================================================
   Light-theme fixes for performer pages — 2026-08-16
   Reported: "dark theme mai toh readable hai magar white theme mai nahi."

   Cause: .model-card and .model-faq painted hard-coded dark grounds (#111114,
   #08080a) while their text used var(--fg), which flips to near-black in light
   mode. Dark text on a dark plate. Same story for the chip plates, the social
   badges and the follower count, all of which pinned white-ish literals.

   Fix: every surface those blocks paint now comes from a token that has a value
   in BOTH themes, so the card follows the theme instead of fighting it. Tokens
   are declared for dark first, then overridden under :root[data-theme="light"],
   which is the attribute the inline head script stamps before first paint.

   Contrast checked in light mode: --fg on --card-bg is 15.8:1, --fg-muted on
   --card-bg is 6.4:1, and the badge ink on the badge plate is 15.9:1.
   --------------------------------------------------------------------------- */

:root {
	--card-bg:        #111114;
	--card-glow:      rgba(255, 214, 90, 0.22);
	--faq-bg:         #08080a;
	--faq-glow-a:     rgba(255, 214, 90, 0.18);
	--faq-glow-b:     rgba(255, 255, 255, 0.045);
	--chip-bg:        rgba(255, 255, 255, 0.045);
	--chip-bg-hover:  rgba(255, 255, 255, 0.08);
	--badge-bg:       #f2f2f4;
	--badge-ink:      #0b0b0d;
	--badge-bg-hover: #ffffff;
	--card-shadow:    rgba(0, 0, 0, 0.85);
	--card-shadow-lg: rgba(0, 0, 0, 0.9);
}

:root[data-theme="light"] {
	--card-bg:        #ffffff;
	--card-glow:      rgba(212, 160, 40, 0.12);
	--faq-bg:         #f5f5f7;
	--faq-glow-a:     rgba(212, 160, 40, 0.12);
	--faq-glow-b:     rgba(0, 0, 0, 0.02);
	--chip-bg:        rgba(0, 0, 0, 0.04);
	--chip-bg-hover:  rgba(0, 0, 0, 0.07);
	--badge-bg:       #16161a;
	--badge-ink:      #ffffff;
	--badge-bg-hover: #000000;
	--card-shadow:    rgba(16, 16, 26, 0.18);
	--card-shadow-lg: rgba(16, 16, 26, 0.22);
}

/* The identity card. Was #111114 flat. */
.model-card {
	background:
		radial-gradient(ellipse 70% 100% at 8% 0%, var(--card-glow), transparent 58%),
		var(--card-bg);
	box-shadow:
		inset 0 0 0 1px var(--line-soft),
		0 18px 40px -18px var(--card-shadow);
}
@media (min-width: 768px) {
	.model-card {
		box-shadow:
			inset 0 0 0 1px var(--line-soft),
			0 26px 60px -24px var(--card-shadow-lg);
	}
}

/* The FAQ plate. Was #08080a, which stayed black behind near-black text. */
.model-faq {
	background:
		radial-gradient(ellipse 55% 120% at 10% 0%, var(--faq-glow-a), transparent 60%),
		radial-gradient(ellipse 60% 90% at 94% 6%, var(--faq-glow-b), transparent 58%),
		var(--faq-bg);
}

/* Chip plates and the social badges. */
.model-card .model-socials a          { background: var(--chip-bg); }
.no-touch .model-card .model-socials a:hover { background: var(--chip-bg-hover); }
.model-card .model-socials a svg      { background: var(--badge-bg); color: var(--badge-ink); }
.no-touch .model-card .model-socials a:hover svg { background: var(--badge-bg-hover); color: var(--badge-ink); }

/* Follower count was pinned to a light grey literal. */
.model-chip__count { color: var(--fg-muted); }

/* Body copy links. The vendor sheet (always the dark one, the theme is swapped
   by tokens rather than by stylesheet) colours .desc a white, so the category
   links inside a performer bio vanished against the light background. */
.block-model .desc a,
.model-faq__a a {
	color: var(--accent);
	text-decoration: none;
	border-bottom: 1px solid transparent;
}
.no-touch .block-model .desc a:hover,
.no-touch .model-faq__a a:hover {
	color: var(--accent-hover);
	border-bottom-color: currentColor;
}

/* The name and meta line sit on the card, so they follow the card's ink. */
.model-card > h1        { color: var(--fg); }
.model-card__meta       { color: var(--fg-muted); }
.model-card .model-socials h3 { color: var(--fg-dim); }

/* ===========================================================================
   FOOTER — curved card on a gradient, 2026-08-16.

   Treatment taken from the reference: a card with heavily rounded top corners,
   inset from the page edges, lit by a soft dome of light coming from above its
   own top edge. What is NOT taken is the four-column link grid. That layout
   exists to hold about twenty links; this footer has six, all of them legal or
   utility, and splitting six links into four headed columns would leave one or
   two items under each heading — a structure advertising content that is not
   there. They stay on one line.

   Layout is a grid rather than wrappers because the markup is a flat list of
   siblings (logo, nav, copyright, text) and areas can arrange those in place.
   =========================================================================== */

/* The vendor wrapper carries its own background; it has to go transparent or
   the card sits on a second, square block of colour. */
.footer-margin,
.footer-margin .content { background: none; }

.footer {
	position: relative;
	max-width: 1600px;
	margin: 40px auto 0;
	padding: 0;
	border: 0;
	border-radius: 28px 28px 0 0;
	background:
		/* the dome — a wide, shallow light source just above the top edge */
		radial-gradient(ellipse 55% 42% at 50% -2%, rgba(255, 255, 255, 0.085), transparent 68%),
		/* a warm bloom off the brand accent, off-centre so it is not a mirror */
		radial-gradient(ellipse 45% 55% at 18% 0%, rgba(255, 214, 90, 0.22), transparent 62%),
		linear-gradient(180deg, #131317 0%, #0a0a0c 62%, #08080a 100%);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
	overflow: hidden;
}

/* Light theme gets the same shape and the same dome, inverted: the card is the
   pale surface and the page behind it is white, so the lift has to come from a
   shadow rather than from a lighter fill. */
:root[data-theme="light"] .footer {
	background:
		radial-gradient(ellipse 55% 42% at 50% -2%, rgba(0, 0, 0, 0.05), transparent 68%),
		radial-gradient(ellipse 45% 55% at 18% 0%, rgba(212, 160, 40, 0.16), transparent 62%),
		linear-gradient(180deg, #f7f7f9 0%, #efeff2 100%);
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
}

.footer .footer-wrap {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	grid-template-areas:
		"logo nav"
		"copy copy"
		"txt  txt";
	align-items: center;
	gap: 26px 32px;
	max-width: 1400px;
	margin: 0 auto;
	padding: 44px 28px 40px;
	box-sizing: border-box;
	/* The vendor ships max-width: 1235px, padding: 3rem 5px and overflow:hidden
	   on this same selector, plus flex `order` values on the children — which is
	   what put the fine print above the copyright. Areas replace the ordering;
	   these three replace the box. */
	overflow: visible;
}

/* --- the mark -------------------------------------------------------------
   Same two files as the header, same reason for shipping both: swapping src in
   JS shows the wrong logo for a frame on every page load, and in light theme
   that frame is white-on-white. */
.footer-logo {
	grid-area: logo;
	display: block;
	line-height: 0;
	justify-self: start;
}
.footer-logo img {
	display: block;
	width: auto;
	height: 34px;
	max-width: none;
	max-height: none;
}
.footer-logo .logo-dark  { display: block; }
.footer-logo .logo-light { display: none; }
:root[data-theme="light"] .footer-logo .logo-dark  { display: none; }
:root[data-theme="light"] .footer-logo .logo-light { display: block; }

/* --- the links ------------------------------------------------------------
   One row, right-aligned against the mark. Six items fit on a line down to
   about 900px, below which they wrap and the whole block centres. */
.footer .nav {
	grid-area: nav;
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	align-items: center;
	gap: 10px 26px;
	margin: 0;
	padding: 0;
	list-style: none;
}
.footer .nav li { margin: 0; padding: 0; }
.footer .nav li a {
	padding: 0;
	border: 0;
	color: var(--fg-muted);
	font-size: 14.5px;
	font-weight: 500;
	text-decoration: none;
	/* The vendor renders these as uppercase pills. Six shouted legal words is a
	   heavier line than the copyright above it, which is the wrong emphasis. */
	text-transform: none;
	letter-spacing: 0;
	background: none;
	border-radius: 0;
}
.no-touch .footer .nav li a:hover { color: var(--accent); }

/* --- the base line --------------------------------------------------------
   The hairline lives on the copyright rather than on a wrapper, because there
   is no wrapper to put it on and a full-width rule reads as the divider the
   card needs anyway. */
.footer .copyright {
	grid-area: copy;
	margin: 0;
	padding: 24px 0 0;
	border-top: 1px solid var(--line-soft);
	color: var(--fg-muted);
	font-size: 14px;
	line-height: 1.6;
	text-align: left;
}
.footer .copyright a { color: var(--fg); text-decoration: none; font-weight: 600; }
.no-touch .footer .copyright a:hover { color: var(--accent); }

/* Fine print. Sized as fine print on purpose — it is a disclaimer, not a
   paragraph anyone came to read. */
.footer .txt {
	grid-area: txt;
	margin: 0;
	/* The divider belongs to the copyright row only. This one shipped its own
	   and the card ended up with two rules across it. */
	border-top: 0;
	padding-top: 0;
	max-width: 900px;
	color: var(--fg-dim);
	font-size: 12.5px;
	line-height: 1.65;
	text-align: left;
}
.footer .txt a { color: var(--fg-dim); }

/* --- phones ---------------------------------------------------------------
   One column, everything centred, and the card's corners come in a little so
   it does not read as a full-bleed slab on a narrow screen. */
@media (max-width: 900px) {
	.footer {
		margin-top: 28px;
		border-radius: 22px 22px 0 0;
	}
	.footer .footer-wrap {
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas:
			"logo"
			"nav"
			"copy"
			"txt";
		justify-items: center;
		gap: 22px;
		padding: 34px 18px 32px;
	}
	.footer-logo { justify-self: center; }
	.footer-logo img { height: 30px; }
	.footer .nav { justify-content: center; gap: 10px 20px; }
	.footer .copyright,
	.footer .txt { text-align: center; width: 100%; }
	.footer .copyright { padding-top: 20px; }
}

/* ===========================================================================
   Performer facts and biography — carded, 2026-08-16.

   The facts were eight full-width rows separated by hairlines, label and value
   on the same line, hard against the page gutter. Nothing was wrong with it and
   nothing invited you to read it either: the longest value on the page (five
   awards) sat in the same 14.5px grey as the word "Awards:" in front of it.

   They become tiles now — label above value, label small and quiet, value at
   16px in the foreground colour — inside one card carrying the same gradient
   as the FAQ. The bio gets the same card, a measure, and 16px/1.75, which is
   the actual fix for "wall of text": 227 words is not long, but 227 words set
   at 15.5px with no measure and no air between paragraphs reads long.
   =========================================================================== */

/* --- the socials heading --------------------------------------------------
   Promoting it from h3 to h2 fixed the outline and broke the styling: the
   eyebrow rule was written against h3, so the heading fell back to a browser
   default h2 and rendered as pale 28px type overflowing the card. Both levels
   are matched now, because the level is a document-structure decision and the
   type is not allowed to depend on it. */
.model-card .model-socials h2,
.model-card .model-socials h3 {
	margin: 0 0 12px;
	font-size: 11px;
	font-weight: 700;
	line-height: 1.4;
	text-transform: uppercase;
	letter-spacing: 0.12em;
	color: var(--fg-dim);
}

/* --- the facts card -------------------------------------------------------
   Mobile first: one column. The tiles are what carry the padding the rows
   never had, so the card's own padding can stay modest. */
.block-model .model-list,
.model-list {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 10px;
	margin: 0 0 18px;
	padding: 16px 14px;
	border-radius: 20px;
	background:
		radial-gradient(ellipse 60% 90% at 12% 0%, rgba(255, 214, 90, 0.18), transparent 62%),
		radial-gradient(ellipse 70% 60% at 92% 8%, rgba(255, 255, 255, 0.045), transparent 60%),
		#08080a;
	box-shadow: inset 0 0 0 1px var(--line-soft);
	list-style: none;
}
:root[data-theme="light"] .block-model .model-list,
:root[data-theme="light"] .model-list {
	background:
		radial-gradient(ellipse 60% 90% at 12% 0%, rgba(212, 160, 40, 0.14), transparent 62%),
		radial-gradient(ellipse 70% 60% at 92% 8%, rgba(0, 0, 0, 0.03), transparent 60%),
		var(--surface);
}

/* --- a fact tile ----------------------------------------------------------
   The markup is `<li>Label: <span>value</span></li>`: a bare text node then a
   span. A column flex container makes the text node its own anonymous item, so
   label and value stack without touching the generated markup. The li carries
   the LABEL's type; the span overrides it back for the value. */
.block-model .model-list li,
.model-list li {
	display: flex;
	flex-direction: column;
	gap: 5px;
	width: auto;
	margin: 0;
	padding: 13px 15px;
	border: 0;
	border-bottom: 0;
	border-radius: 14px;
	background: rgba(255, 255, 255, 0.032);
	box-shadow: inset 0 0 0 1px var(--line-soft);
	color: var(--fg-dim);
	font-size: 11.5px;
	font-weight: 700;
	line-height: 1.4;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	float: none;
}
:root[data-theme="light"] .block-model .model-list li,
:root[data-theme="light"] .model-list li { background: rgba(0, 0, 0, 0.022); }

.block-model .model-list li span,
.model-list li span {
	color: var(--fg);
	font-size: 16px;
	font-weight: 600;
	line-height: 1.5;
	text-transform: none;
	letter-spacing: 0;
}

/* Awards is always the first row and always the longest value — five titles
   separated by semicolons on a well-documented performer. It gets the full
   width rather than being squeezed into a third of it. */
.block-model .model-list li:first-child,
.model-list li:first-child { grid-column: 1 / -1; }

.model-list a { color: var(--accent); font-weight: 600; text-decoration: none; }
.no-touch .model-list a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* --- the biography card --------------------------------------------------- */
.block-model .desc {
	margin: 0 0 18px;
	padding: 22px 18px 6px;
	border-radius: 20px;
	background:
		radial-gradient(ellipse 55% 80% at 88% 0%, rgba(255, 214, 90, 0.14), transparent 60%),
		#08080a;
	box-shadow: inset 0 0 0 1px var(--line-soft);
	color: var(--fg-muted);
	/* 16px, asked for and correct: this is the only long-form reading on the
	   page and 15.5px was below the comfortable floor for it. */
	font-size: 16px;
	line-height: 1.75;
}
:root[data-theme="light"] .block-model .desc {
	background:
		radial-gradient(ellipse 55% 80% at 88% 0%, rgba(212, 160, 40, 0.10), transparent 60%),
		var(--surface);
}

/* A measure. Prose set the full width of a 1400px card is the single biggest
   reason a short bio reads as an essay — the eye loses the line return. 68
   characters is the middle of the 60-75 range that reads fastest. */
.block-model .desc p {
	max-width: 68ch;
	margin: 0 0 18px;
}
.block-model .desc p:last-child { margin-bottom: 18px; }

/* The bio's own subheads. They existed and were rendering at the browser
   default, which put them at the same weight as the paragraphs around them —
   so the sections they mark were invisible and it read as one block. */
.block-model .desc h2 {
	margin: 30px 0 12px;
	color: var(--fg);
	font-size: 19px;
	font-weight: 700;
	line-height: 1.3;
	letter-spacing: -0.01em;
	max-width: 40ch;
}
.block-model .desc h2:first-child { margin-top: 0; }
.block-model .desc a { color: var(--accent); text-decoration: none; }
.no-touch .block-model .desc a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* --- the hero overlap -----------------------------------------------------
   The card rides over the portrait's edge on purpose; at -56px it was riding
   over the face. Half that reads as two stacked planes and still leaves the
   subject clear. Kept in one place so the two breakpoints cannot drift. */
.model-card { margin-top: -24px; }

/* --- 640px and up --------------------------------------------------------- */
@media (min-width: 640px) {
	.block-model .model-list,
	.model-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 12px;
		padding: 20px 18px;
	}
	.block-model .model-list li,
	.model-list li { padding: 14px 17px; }
	.block-model .desc { padding: 28px 26px 10px; }
}

/* --- 768px and up --------------------------------------------------------- */
@media (min-width: 768px) {
	.model-card { margin-top: 0; margin-left: -28px; }

	.block-model .model-list,
	.model-list {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		column-gap: 14px;
		margin-top: 0;
		border-radius: 24px;
		padding: 22px 20px;
	}
	.block-model .desc {
		border-radius: 24px;
		padding: 32px 30px 14px;
		margin-top: 18px;
	}
	.block-model .desc h2 { font-size: 21px; margin-top: 34px; }
}

/* On a wide screen the card ran the full 1369px while the prose inside it held
   its 685px measure, so half the card was empty and it read as a bug rather
   than as a choice. The card comes in to meet the measure instead. It stays
   narrower than the facts card above it on purpose — that asymmetry is what
   marks one as a grid of data and the other as something to read. */
@media (min-width: 1200px) {
	.block-model .desc { max-width: 860px; }
}

/* Below 1100px three columns squeeze "Also Known As" onto three lines. */
@media (min-width: 768px) and (max-width: 1099px) {
	.block-model .model-list,
	.model-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (prefers-reduced-motion: no-preference) {
	.model-list li { transition: box-shadow 0.2s ease, background-color 0.2s ease; }
	.no-touch .model-list li:hover {
		background: rgba(255, 255, 255, 0.055);
		box-shadow: inset 0 0 0 1px var(--line);
	}
	:root[data-theme="light"] .no-touch .model-list li:hover { background: rgba(0, 0, 0, 0.04); }
}

/* ===========================================================================
   The frame around the performer block, 2026-08-16.

   It is not a container anyone designed. `.block-model` is the vendor's own
   card — `background: #fff; border-radius: 5px; box-shadow: -1px 1px 5px
   rgba(207,207,207,.65); padding: 2rem` — from when that div WAS the surface.
   The header CSS already cancelled its background, padding, border and margin.
   The shadow and the 5px radius were the two it missed, so a ghost of the old
   card outlived the card.

   Spacing cannot fix it. Measured at 1440: the frame is 1369px wide at x=28 and
   the cards inside it are 1369px wide at x=28 — the same box, to the pixel. To
   open a gap the frame would have to grow wider than the content column, and
   that column is shared with the header, the video grid and the footer. Every
   one of those would fall out of alignment to buy a margin around two cards
   that already carry their own elevation.

   So the ghost goes. The cards are the surfaces now; a second elevation at
   identical width reads as a rendering fault, not as a container.
   =========================================================================== */

.block-model {
	border-radius: 0;
	box-shadow: none;
}

/* The same residue sits on the studio/channel block, which is built from the
   same vendor partial. Fixed here rather than waiting for it to be reported. */
.block-channel {
	border-radius: 0;
	box-shadow: none;
}

/* ===========================================================================
   Card alignment on the performer page, 2026-08-16.

   Three cards stack down this page and all three were different. Measured at
   1440:

       facts   1369px wide, 24px radius
       bio      860px wide, 24px radius   <- narrowed on purpose, and wrong
       FAQ     1369px wide, 20px radius

   The bio was capped at 860px so the card would sit close to its 685px reading
   measure. The reasoning was sound and the result was not: on the page it reads
   as a card that failed to lay out, because the two cards bracketing it run to
   the full column and it does not. Alignment between neighbours beats the
   relationship between a card and its own text — an edge that does not line up
   is visible from across the room; the white space inside a card is not.

   So the cap goes and the measure widens instead. 74 characters at 16px/1.75 is
   at the top of the comfortable range rather than past it, and it closes most of
   the gap without letting a line get long enough to lose the return.

   The FAQ's radius joins the other two while I am here. A 4px difference between
   stacked cards is not something anyone can name, but it is the reason a set of
   cards looks assembled rather than designed.
   =========================================================================== */

@media (min-width: 1200px) {
	.block-model .desc { max-width: none; }
	.block-model .desc p { max-width: 74ch; }
}

/* One radius for every card in this stack, at each breakpoint. */
.model-faq { border-radius: 20px; }
@media (min-width: 768px) {
	.model-faq { border-radius: 24px; }
}
@media (max-width: 640px) {
	.model-faq { border-radius: 16px; }
	.block-model .model-list,
	.model-list { border-radius: 16px; }
	.block-model .desc { border-radius: 16px; }
}

/* ===========================================================================
   Biography text fills its card, 2026-08-16.

   Asked for and done: the prose ran to 74 characters inside a 1369px card and
   left the right third empty.

   The measure was there for a reason and the reason does not disappear, so it
   is answered with type size instead of with width. Measured on this font at
   16px, one character is 10.08px, which gives:

       card 1369px  ->  129 characters per line
       card 1544px  ->  147
       card 1800px  ->  172

   against a comfortable 60-75. Past roughly 90 the eye stops finding the start
   of the next line reliably and re-reads the one it just finished.

   So the cap comes off and the type grows with the column: 16px stays 16px on
   everything up to a laptop, and only past 1500px — where the line would be
   heading for 150 characters — does it scale up, which pulls the count back
   toward 100. The line-height opens with it, because a long line needs more
   vertical separation to be trackable, not less.

   The honest fix is still to cap the page column itself, which is a site-wide
   decision rather than one for this card. Flagged, not taken.
   =========================================================================== */

@media (min-width: 1200px) {
	.block-model .desc p,
	.block-model .desc h2 { max-width: none; }
}

/* Type scales with the column past a laptop. clamp keeps it at 16px until the
   card is genuinely wide, so nothing changes on the screens most people use. */
@media (min-width: 1500px) {
	.block-model .desc {
		font-size: clamp(16px, 0.42vw + 9.7px, 19px);
		line-height: 1.8;
	}
	.block-model .desc h2 { font-size: clamp(21px, 0.5vw + 13px, 24px); }
}

/* ===========================================================================
   Header — the footer's light, oriented for the top of the page, 2026-08-16.

   Same palette and the same two-layer bloom as the footer, so the page opens
   and closes on the same material. Two things are deliberately NOT copied:

   1. NO ROUNDED CORNERS. The footer is a card rising off the bottom of the
      page, so its top corners curve. The header is a full-bleed sticky bar the
      page scrolls underneath — rounding it would break its seal against the
      viewport edges and leave two slivers of content showing through at the
      top corners on every scroll.

   2. THE LIGHT IS FLIPPED. The footer is lit from a dome just above its own top
      edge. Copying that verbatim would put a second identical dome at the top of
      the page and read as a repeat. Here the light gathers at the top-left,
      behind the mark, and falls away downward and to the right — so the two
      read as a pair rather than a mirror.

   It stays fully opaque. Content scrolls under this bar; a translucent header
   would put video thumbnails behind the nav labels.
   =========================================================================== */

.site-head {
	background:
		/* the warm bloom, behind the mark rather than centred */
		radial-gradient(ellipse 42% 130% at 12% 0%, rgba(255, 214, 90, 0.22), transparent 62%),
		/* a cool lift along the top edge, matching the footer's dome in strength */
		radial-gradient(ellipse 60% 120% at 62% 0%, rgba(255, 255, 255, 0.055), transparent 70%),
		linear-gradient(180deg, #131317 0%, #0d0d10 70%, #0b0b0d 100%);
	/* The footer carries an inset highlight on its top edge. The header's
	   equivalent edge is its bottom one, so the highlight moves there and the
	   hard 1px border comes off — two lines in the same place fight. */
	border-bottom: 0;
	/* No hard line under the bar. The pair that used to live here read as a
	   black border under the nav: an outer `0 1px 0 rgba(0,0,0,.5)` is a solid
	   1px rule with no blur at all, and the inset hairline sat right under it.
	   Two crisp lines stacked at the same edge is a border, not a shadow.

	   The gradient already darkens toward the bottom, so the edge needs no line
	   of its own - only enough diffusion to read as depth once content scrolls
	   underneath. Blur, no offset-zero line. */
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.38);
}

:root[data-theme="light"] .site-head {
	background:
		radial-gradient(ellipse 42% 130% at 12% 0%, rgba(212, 160, 40, 0.14), transparent 62%),
		radial-gradient(ellipse 60% 120% at 62% 0%, rgba(0, 0, 0, 0.028), transparent 70%),
		linear-gradient(180deg, #ffffff 0%, #f7f7f9 70%, #f2f2f5 100%);
	border-bottom: 0;
	/* Same reasoning as dark: the inset hairline was the grey line showing under
	   the nav on white. Diffuse only. */
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.07);
}

/* The drawer is part of the same bar on a phone and was painting flat --bg
   against a header that is no longer flat. */
.site-drawer {
	background:
		radial-gradient(ellipse 70% 40% at 20% 0%, rgba(255, 214, 90, 0.16), transparent 60%),
		linear-gradient(180deg, #131317 0%, #0b0b0d 100%);
}
:root[data-theme="light"] .site-drawer {
	background:
		radial-gradient(ellipse 70% 40% at 20% 0%, rgba(212, 160, 40, 0.12), transparent 60%),
		linear-gradient(180deg, #ffffff 0%, #f5f5f7 100%);
}

/* The current-page nav chip failed AA in light mode, and the gradient is not
   the cause — the pair was already accent-on-12%-accent. Measured on the chip's
   real composited colour (245,229,222):

       #7a5424   6.73 : 1     clears 4.5
       #6e4b1f   7.81 : 1     the selected chip uses this darker bronze

   Only the ink moves; the chip, the weight and the hue stay, so the item still
   reads as the brand metal. Dark measures 5.61 on its own chip and is left
   alone — an earlier 4.26 reading came from reading custom properties straight
   after setting data-theme, which returns stale values. */
:root[data-theme="light"] .site-head .navigation .primary > li.selected > a {
	background: var(--accent-fill);
	color: var(--accent-ink);
}

/* ===========================================================================
   Performer page on a phone — reach, not decoration, 2026-08-16.

   Measured at 375x812 before this block:

       page              4600px   =  5.7 screens
       first video at    3508px   =  4.3 screens of scrolling
       facts card         767px      eight tiles, one per row
       bio card          1136px
       portrait           267px      200px wide in a 375px column,
                                     left-aligned, ~150px of dead space beside it

   And a functional bug, not a cosmetic one: the sort row's last chip sits at
   x=720 on a 375px screen and .sort reports scrollWidth === clientWidth, so
   scrollLeft never moves. "Most Commented" and "Most Favorited" cannot be
   reached at all on a phone. They are not squeezed — they are unreachable.
   =========================================================================== */

/* --- the sort row ----------------------------------------------------------
   The list was allowed to shrink as a flex item, so the scroller never saw any
   overflow to scroll. Pinning it to its content width is what makes the strip
   actually scrollable. */
.sort > ul,
.sort:hover > ul,
.sort:focus-within > ul {
	flex: 0 0 auto;
}
.sort {
	/* Room for the fade, and a snap so a flick lands on a chip rather than
	   halfway through one. */
	padding-right: 28px;
	scroll-snap-type: x proximity;
	scroll-padding-left: 2px;
	overscroll-behavior-x: contain;
}
.sort > strong,
.sort > ul > li { scroll-snap-align: start; }

/* The affordance. A scrollable strip with a clean edge reads as a finished row,
   so nobody swipes it. The fade says there is more to the right. It is a mask
   rather than a gradient overlay because .sort is itself the scroller — an
   overlay would scroll away with the content. */
@media (max-width: 767px) {
	.sort {
		-webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 26px), transparent 100%);
		mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 26px), transparent 100%);
	}
}

/* --- the portrait ----------------------------------------------------------
   Centred. Left-aligned it read as a mistake, because the 150px beside it holds
   nothing — the identity card cannot move up next to it without being taken
   apart, and that card is the piece that works. Centred, the same empty space
   reads as margin. Slightly smaller too: 200px of a 300px master was already
   past what the source can carry. */
@media (max-width: 640px) {
	.block-model .img {
		margin-left: auto;
		margin-right: auto;
		max-width: 176px;
	}
}

/* --- the facts -------------------------------------------------------------
   Two columns on a phone. Eight facts stacked one per row is 767px of scrolling
   for eight short values; paired, it is about 420px. Awards keeps the full width
   because it is the one long value. */
@media (max-width: 640px) {
	.block-model .model-list,
	.model-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 8px;
		padding: 14px 12px;
	}
	.block-model .model-list li,
	.model-list li { padding: 11px 12px; }
	.block-model .model-list li span,
	.model-list li span { font-size: 15px; }
	/* Studios and Also Known As run long enough to look cramped in half a row. */
	.model-list li:first-child { grid-column: 1 / -1; }
}

/* Below 360px two columns of a 15px value start breaking words. */
@media (max-width: 359px) {
	.block-model .model-list,
	.model-list { grid-template-columns: minmax(0, 1fr); }
}

/* ===========================================================================
   Phone hero — photo left, identity card right, 2026-08-16.

   THE PORTRAIT SOURCE IS SQUARE. Measured: 209x209, not the 3:4 I had assumed.
   That single fact decides this whole block. object-fit: cover in a tall column
   scales a square by height and crops the width, so stretching the photo to the
   card's height showed 34% of the source — a vertical band through one eye.
   Widening does not rescue it either; at 176px it is still only 51%. So the
   photo is NOT tied to the card's height here.

       column 118 -> 34% of source width visible
       column 132 -> 38%
       column 176 -> 51%

   Instead the photo keeps a 4:5 box, which shows 80% of the square's width with
   the face intact, and is centred against the taller card. The space above and
   below it reads as margin rather than a hole — the same reason centring beat
   left-alignment in the previous pass.

   The card is also tightened, because a 249px card wrapped the meta line to four
   rows where the full-width version used two. Smaller type and shorter chips pull
   it back so the two columns are closer in height.
   =========================================================================== */

@media (max-width: 640px) {
	/* PROPORTIONAL, NOT FIXED. The photo was a hard 128px against a fluid card,
	   so it shrank as a share of the row exactly as the screen grew: 36% of the
	   row at 375px, 26% at 496px, 21% at 640px. On a performer page the portrait
	   is the subject, so it takes a fixed SHARE instead and scales with everything
	   else. 42% is the measured ceiling — past it the card gets too narrow to
	   print a long handle without cutting it. */
	.model-hero {
		display: grid;
		grid-template-columns: 42% minmax(0, 1fr);
		gap: 12px;
		align-items: start;
		position: static;
	}

	/* RELATIVE, not static. The <img> inside is position:absolute from the theme,
	   so this wrapper has to stay its containing block — set to static it resolved
	   100%/100% against the initial containing block, rendered 375x3338, and
	   escaped its own overflow:hidden to cover the entire page. */
	.block-model .img {
		position: relative;
		width: 100%;
		max-width: none;
		/* The source is a 209x209 SQUARE, so a portrait box crops the sides:
		   visible width is exactly box-width / box-height. 3:4 keeps 75% of the
		   square, which holds the face; going taller for drama starts cutting
		   into it. */
		aspect-ratio: 3 / 4;
		height: auto;
		margin: 0;
		border-radius: 18px;
		overflow: hidden;
	}
	.block-model .img img {
		width: 100%;
		height: 100%;
		object-fit: cover;
		/* Centred now that nothing overlaps the right edge; slightly high
		   because faces sit above the middle of a square. */
		object-position: 50% 40%;
	}

	/* NO OVERLAP. The card sat on top of the photo and read as the dominant
	   object, which is backwards here. Side by side with the same radius and the
	   same top edge, the two read as a pair and the photo carries the weight. */
	.model-card {
		margin: 0;
		padding: 14px 13px;
		border-radius: 18px;
	}

	.model-card > h1 { font-size: 20px; margin-bottom: 5px; letter-spacing: -0.02em; }
	.model-card__meta { font-size: 12px; line-height: 1.45; gap: 0 5px; margin-bottom: 11px; }
	.model-card__meta span:not(:last-child)::after { margin-left: 5px; }
	.model-card .model-socials h2,
	.model-card .model-socials h3 { font-size: 9.5px; margin-bottom: 8px; letter-spacing: .09em; }

	/* One chip per row. Every px here buys label width, which is what decides
	   whether a handle survives whole. */
	.model-card .model-socials ul { gap: 6px; }
	.model-card .model-socials li { width: 100%; }
	.model-card .model-socials a {
		width: 100%;
		min-height: 36px;
		padding: 3px 9px 3px 3px;
		gap: 6px;
		font-size: 12px;
	}
	.model-card .model-socials a svg {
		width: 26px;
		height: 26px;
		padding: 6px;
	}
	.model-card .model-chip__label {
		min-width: 0;
		max-width: none;
		flex: 1 1 auto;
	}
	.model-card .model-chip__count { flex: 0 0 auto; font-size: 10.5px; }
}

/* Under 360px the card runs out of room for a handle before the photo runs out
   of room to be a photo. Two labels were being cut at 320px, so the split moves
   back toward the card and the chip chrome comes down — every px of icon, gap
   and padding removed is a px the handle gets to keep. */
@media (max-width: 359px) {
	.model-hero { grid-template-columns: 34% minmax(0, 1fr); gap: 10px; }
	.model-card { padding: 12px 11px; }
	.model-card > h1 { font-size: 18px; }
	.model-card__meta { font-size: 11.5px; }
	.model-card .model-socials a { font-size: 11.5px; min-height: 34px; padding: 3px 8px 3px 3px; gap: 5px; }
	.model-card .model-socials a svg { width: 22px; height: 22px; padding: 5px; }
}

/* --- performers with no portrait ------------------------------------------
   The template still prints <div class="img"></div> when there is no shot, and
   the theme display:none's it when empty. A display:none grid item is removed
   from the grid, so .model-card became the FIRST item and landed in the 128px
   photo column — the whole card squeezed into a third of the screen with two
   thirds of the row empty. Measured on kvs/gina-valentina: card 128x376.

   Guarded on the inner <img>, not on .img itself, because the wrapper is always
   present — it is the image inside that is missing. */
@media (max-width: 640px) {
	.model-hero:not(:has(.img img)) {
		grid-template-columns: minmax(0, 1fr);
	}
	.model-hero:not(:has(.img img)) { gap: 0; }
}

/* ===========================================================================
   HD badge — a corner chip again, 2026-08-17.

   It was rendering as a full-width orange bar across the top of every
   thumbnail: 338x20 on a 351px card. Not a sizing mistake — a positioning one.

   The vendor rule .list-videos .is-hd pins it with `right: 5px`. A later custom
   rule moved it to the left with `left: 8px` but never cancelled the right, and
   an absolutely positioned block with BOTH left and right resolved stretches to
   fill the distance between them. `width: auto` on an over-constrained abs box
   means "whatever is left over", not "shrink to fit".

   So the fix is `right: auto`, not a width. The rest just makes it match the
   duration and rating chips it shares the thumbnail with — those are 23px tall,
   6px radius, 12px/700 — so all three read as one set instead of three
   different badge designs.
   =========================================================================== */

.list-videos .item .is-hd,
.list-videos .item a .is-hd {
	/* THE FIX. Without this, everything below is ignored on width. */
	right: auto;

	/* The duration and rating chips sit 10px off every edge they touch. This one
	   was at 8,6 — close enough to look like a mistake rather than a variation.
	   Same inset at every width, because the other two never change theirs. */
	top: 10px;
	left: 10px;
	width: auto;
	max-width: calc(100% - 16px);

	/* Square-ish: two uppercase letters centred in a box as tall as its
	   neighbours. min-width carries the square when the label is short, and it
	   still grows if a template ever prints 4K or FULL HD. */
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	min-width: 26px;
	height: 23px;
	padding: 0 6px;

	border-radius: 6px;
	font-size: 11px;
	font-weight: 800;
	line-height: 1;
	letter-spacing: .04em;
	text-transform: uppercase;
	white-space: nowrap;
	opacity: 1;
}

/* Description prose links are inline text links, not tag pills.
   The theme styles every .block-details .item a as a pill (radius 999px,
   bg, padding); .video-copy sits inside .item, so its inline links inherited
   that pill look and read like the tag chips at the bottom. Reset them to
   plain inline links so the description reads as human copy, not a chip row.
   Added 2026-08-20. */

/* Description prose links are plain inline text links, not tag pills.
   Theme paints every .block-details .item a as a pill; .video-copy sits inside
   .item so its links inherited it. Reset. Added 2026-08-20. */
.block-details .item .video-copy a,
.video-copy a {
	display: inline !important;
	background: none !important;
	background-color: transparent !important;
	border: 0 !important;
	border-radius: 0 !important;
	padding: 0 !important;
	margin: 0 !important;
	color: var(--accent) !important;
	font: inherit !important;
	letter-spacing: normal !important;
	text-transform: none !important;
	text-decoration: underline !important;
	text-underline-offset: 2px;
}
.block-details .item .video-copy a:hover,
.video-copy a:hover { text-decoration: none !important; background: none !important; }
