/* ===========================================================================
   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:        #ff6a1f;
	--accent-hover:  #ff8340;
	--accent-ink:    #14100c;
	--accent-soft:   rgba(255, 106, 31, .14);

	/* 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);
	--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(255, 106, 31, .75);
	--glow-soft: rgba(255, 106, 31, .45);

	/* 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(255, 106, 31, .26);

	/* 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 because #ff6a1f on white is only 2.9:1 — fine for a filled
   button, too weak for text on a pale background.
   --------------------------------------------------------------------------- */

: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:        #e2560d;
	--accent-hover:  #c74809;
	--accent-ink:    #ffffff;
	--accent-soft:   rgba(226, 86, 13, .12);

	--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(226, 86, 13, .55);
	--glow-soft: rgba(226, 86, 13, .28);

	--cta-shadow: rgba(226, 86, 13, .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);
	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;
}


/* ---------------------------------------------------------------------------
   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);
	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-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-soft);
	color: var(--accent);
	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);
	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);
}
.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);
	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);
	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);
	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);
	color: var(--accent-ink);
	font-size: 10.5px;
	font-weight: 800;
	letter-spacing: .04em;
	line-height: 1.3;
	text-indent: 0;
	background-image: none;
	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);
	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);
	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);
	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);
	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-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-soft);
		color: var(--accent);
		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;
	}
}
