<?php
error_reporting(0);
ini_set('display_errors', 0);
require_once __DIR__ . '/seo_texts.php';
require_once __DIR__ . '/seo_sub.php';
require_once __DIR__ . '/seo_sub_de.php';
require_once __DIR__ . '/lang.php';

define('SITE_URL',  'https://sex-videochat.info');
define('USER_ID',   '492b59a9925d01876c059022ef32fa6f9949ef373e4179aa08008786798f6032');
define('API_KEY',   '22f4ea13b6dd0a08a0d9');
define('CACHE_DIR', __DIR__ . '/cache');
define('CACHE_TTL', 1800);
$_siteUrl = siteUrl();

// --- Parse tag from clean URL path or ?tag= ---
$path = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
$tag  = $_GET['tag'] ?? '';
if (!$tag && $path) {
    $tag = preg_replace('/[^a-z\/\-]/', '', strtolower($path));
}
$tag = $tag ?: 'girls';

// --- SEO helpers ---
$topCats = ['girls'=>t('nav_girls','Girls'),'men'=>t('nav_men','Guys'),'couples'=>t('nav_couples','Couples'),'trans'=>t('nav_trans','Trans')];
$topTag  = explode('/', $tag)[0];
$subSlug = strpos($tag,'/') !== false ? explode('/',$tag)[1] : null;

// Human-readable label for subcategory slugs
$subLabels = [
    'asian'=>'Asian','ebony'=>'Ebony','latin'=>'Latina','russian'=>'Russian',
    'indian'=>'Indian','arab'=>'Arab','white'=>'White','mixed'=>'Mixed',
    'ukrainian'=>'Ukrainian','colombian'=>'Colombian','italian'=>'Italian',
    'german'=>'German','french'=>'French','spanish'=>'Spanish','japanese'=>'Japanese',
    'chinese'=>'Chinese','korean'=>'Korean','thai'=>'Thai','vietnamese'=>'Vietnamese',
    'pinay'=>'Pinay','turkish'=>'Turkish','romanian'=>'Romanian','czech'=>'Czech',
    'hungarian'=>'Hungarian','polish'=>'Polish','brazilian'=>'Brazilian',
    'mexican'=>'Mexican','venezuelan'=>'Venezuelan','argentinian'=>'Argentinian',
    'australian'=>'Australian','canadian'=>'Canadian','swedish'=>'Swedish',
    'scandinavian'=>'Scandinavian','srilankan'=>'Sri Lankan',
    'teens'=>'Teen 18+','milfs'=>'MILF','mature'=>'Mature','grannies'=>'Granny',
    'bbw'=>'BBW','petite'=>'Petite','curvy'=>'Curvy','athletic'=>'Athletic',
    'big-tits'=>'Big Tits','big-ass'=>'Big Ass','small-tits'=>'Small Tits',
    'blondes'=>'Blonde','brunettes'=>'Brunette','redheads'=>'Redhead',
    'hairy'=>'Hairy','tattoos'=>'Tattooed','piercings'=>'Pierced',
    'anal'=>'Anal','squirt'=>'Squirt','lesbians'=>'Lesbian','bdsm'=>'BDSM',
    'big-cocks'=>'Big Cocks','bears'=>'Bears','twinks'=>'Twinks',
    'new'=>'New','best'=>'Best','hd'=>'HD','vr'=>'VR','lovense'=>'Lovense',
    'young'=>'Young','pregnant'=>'Pregnant','feet'=>'Feet','smoking'=>'Smoking',
    'cosplay'=>'Cosplay','goth'=>'Goth','emo'=>'Emo','milfs'=>'MILF',
    'african'=>'African','kenyan'=>'Kenyan','south-african'=>'South African',
];

$baseLabel = t('base_' . $topTag, 'Cam Girls');
$baseSite  = t('base_site_' . $topTag, 'stripchat cam girls');

if ($subSlug) {
    $subLabel  = subLabel($subSlug);
    $catSuffix = t('sub_' . $topTag, 'Cam Girls');
    $title     = "{$subLabel} {$baseLabel} — " . t('sub_title_suffix', 'Free Live Cams');
    $desc      = tf('sub_desc', 'Watch live %s %s models performing. Free HD webcam streams online 24/7.', $subLabel, $baseSite);
    $heading   = "{$subLabel} {$catSuffix}";
} else {
    $subLabel = null;
    $topLabel = $topCats[$topTag] ?? 'Girls';
    $topSEO   = [
        'girls'   => ['t'=>t('seo_girls_t','Live Cam Girls stripchat - Watch Free Webcam Models Online'),    'd'=>t('seo_girls_d','Watch thousands of live cam girls streaming free. HD webcams 24/7. No registration.'), 'h'=>t('seo_girls_h','Live Cam Girls')],
        'men'     => ['t'=>t('seo_men_t','Gay stripchat Cams - Live Male Webcam Models Online'),             'd'=>t('seo_men_d','Watch gay stripchat models live. Free access to hundreds of male cams.'),             'h'=>t('seo_men_h','Gay Live Cams')],
        'couples' => ['t'=>t('seo_couples_t','Couples stripchat Cams - Watch Live Couple Webcams Online'),   'd'=>t('seo_couples_d','Watch couples stripchat live shows for free. HD streams available now.'),          'h'=>t('seo_couples_h','Couples Live Cams')],
        'trans'   => ['t'=>t('seo_trans_t','Shemale stripchat Cams - Live Trans Webcam Models Online'),      'd'=>t('seo_trans_d','Watch shemale stripchat models streaming free in HD. Browse trans performers now.'),  'h'=>t('seo_trans_h','Shemale Live Cams')],
    ];
    $m       = $topSEO[$topTag] ?? $topSEO['girls'];
    $title   = $m['t'];
    $desc    = $m['d'];
    $heading = $m['h'];
}
$topLabel = $topCats[$topTag] ?? 'Girls';

// Canonical URL
$canonical = $_siteUrl . '/' . $tag . '/';

// Schema.org
$ldJson = json_encode([
    '@context' => 'https://schema.org',
    '@graph'   => [
        ['@type'=>'WebSite','@id'=>$_siteUrl.'/#website','url'=>$_siteUrl.'/','name'=>$_SERVER['HTTP_HOST']],
        ['@type'=>'CollectionPage','name'=>$heading,'url'=>$canonical,'description'=>$desc,
         'breadcrumb'=>['@type'=>'BreadcrumbList','itemListElement'=>array_values(array_filter([
             ['@type'=>'ListItem','position'=>1,'name'=>t('breadcrumb_home','Home'),'item'=>$_siteUrl.'/'],
             $subLabel ? ['@type'=>'ListItem','position'=>2,'name'=>$topLabel,'item'=>$_siteUrl.'/'.$topTag.'/'] : null,
             ['@type'=>'ListItem','position'=>($subLabel?3:2),'name'=>$heading,'item'=>$canonical],
         ]))]],
    ],
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

function h(string $s): string { return htmlspecialchars($s, ENT_QUOTES|ENT_SUBSTITUTE, 'UTF-8'); }

function modelCard(array $m): string {
    $name    = htmlspecialchars($m['username'] ?? '', ENT_QUOTES, 'UTF-8');
    $url     = '/model/' . rawurlencode($m['username'] ?? '');
    $img     = htmlspecialchars($m['snapshotUrl'] ?? $m['popularSnapshotUrl'] ?? $m['previewUrlThumbSmall'] ?? '', ENT_QUOTES, 'UTF-8');
    $country = strtoupper($m['modelsCountry'] ?? '');
    $viewers = (int)($m['viewersCount'] ?? 0);
    $fav     = (int)($m['favoritedCount'] ?? 0);
    $hd      = !empty($m['broadcastHD']) ? '<span class="badge b-hd">HD</span>' : '';
    $vr      = !empty($m['broadcastVR']) ? '<span class="badge b-vr">VR</span>' : '';
    $isNew   = !empty($m['isNew'])       ? '<span class="badge b-new">NEW</span>' : '';
    $hasGoal = (!empty($m['goalMessage']) || ($m['neededForGoal'] ?? 0) > 0) ? '<span class="badge b-goal">GOAL</span>' : '';
    $vCount  = $viewers > 0 ? '<span class="card-viewers">' . ($viewers >= 1000 ? round($viewers/1000,1).'K' : $viewers) . '</span>' : '';
    $flagStr = '';
    if (strlen($country) === 2) {
        $flagStr = implode('', array_map(fn($c) => mb_chr(0x1F1E6 + ord($c) - 65), mb_str_split($country)));
    }
    $pct     = 0;
    if (($m['neededForGoal'] ?? 0) > 0) {
        $pct = min(100, round(($m['earnedForGoal'] ?? 0) / $m['neededForGoal'] * 100));
    }
    $goalBar = $pct > 0 ? '<div class="card-goal-bar"><div class="card-goal-fill" style="width:'.$pct.'%"></div></div>' : '';
    $favHtml = $fav > 0 ? '<span class="card-fav">&#9829; ' . ($fav >= 1000 ? round($fav/1000,1).'K' : $fav) . '</span>' : '';
    $fallback = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 80 80%22%3E%3Crect width=%2280%22 height=%2280%22 fill=%22%23181820%22/%3E%3C/svg%3E';
    return '<a class="model-card" href="'.$url.'" data-u="'.$name.'" aria-label="'.$name.' live webcam">'
        .'<div class="card-thumb">'
        .'<img class="card-img" src="'.$img.'" alt="'.$name.' live cam" loading="lazy" decoding="async" width="320" height="240" onerror="this.src=\''.$fallback.'\'">'
        .'<div class="card-overlay" aria-hidden="true"></div>'
        .'<div class="play-icon" aria-hidden="true"><svg viewBox="0 0 48 48" fill="none"><circle cx="24" cy="24" r="24" fill="rgba(0,0,0,.55)"/><polygon points="19,15 36,24 19,33" fill="white"/></svg></div>'
        .'<div class="card-badges" aria-hidden="true">'.$hd.$vr.$isNew.$hasGoal.'</div>'
        .'<span class="card-online" aria-hidden="true"></span>'
        .$vCount.$goalBar
        .'</div>'
        .'<div class="card-info">'
        .'<div class="card-name">'.$name.'</div>'
        .'<div class="card-meta">'.$flagStr.'<span>'.$country.'</span>'.$favHtml.'</div>'
        .'</div>'
        .'</a>';
}

?><!DOCTYPE html>
<html lang="<?= t('lang_attr','en') ?>">
<head>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-NQM6FB2X');</script>
<!-- End Google Tag Manager -->
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XS6BT34GJP"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XS6BT34GJP');
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">

<title><?= h($title) ?></title>
<meta name="description" content="<?= h($desc) ?>">
<meta name="robots" content="index, follow, max-image-preview:large">
<link rel="canonical" href="<?= h($canonical) ?>">
<?= hreflangTags('/' . ($tag === 'girls' ? '' : $tag . '/')) ?>

<meta property="og:type" content="website">
<meta property="og:site_name" content="<?= $_SERVER['HTTP_HOST'] ?>">
<meta property="og:title" content="<?= h($title) ?>">
<meta property="og:description" content="<?= h($desc) ?>">
<meta property="og:url" content="<?= h($canonical) ?>">

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="<?= h($title) ?>">
<meta name="twitter:description" content="<?= h($desc) ?>">

<script type="application/ld+json"><?= $ldJson ?></script>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="stylesheet" href="/style.css">
</head>
<body>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NQM6FB2X"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

<header class="site-header" role="banner">
  <div class="header-row">
    <a href="/" class="logo" aria-label="sex-videochat.info - Home"><span class="logo-text">Sex-videochat<span class="logo-tld">.info</span></span></a>
    <div class="search-wrap" role="search">
      <svg class="search-icon" width="15" height="15" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
        <circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
      </svg>
      <input type="search" id="searchInput" placeholder="<?= t('search_placeholder','Search models…') ?>" aria-label="Search cam models" autocomplete="off">
    </div>
    <div class="hdr-actions">
      <?= langSwitcherHtml() ?>
      <button class="sb-toggle" id="sbToggle" aria-label="Toggle categories" aria-expanded="false">
        <svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
      </button>
    </div>
  </div>

  <nav class="cat-nav" aria-label="Model categories">
    <a class="cat-btn<?= $topTag==='girls'&&!$subSlug?' active':'' ?>" href="/">
      <span class="cat-dot" aria-hidden="true"></span><?= t('nav_girls','Girls') ?>
    </a>
    <a class="cat-btn<?= $topTag==='men'&&!$subSlug?' active':'' ?>" href="/men/">
      <span class="cat-dot" aria-hidden="true"></span><?= t('nav_men','Guys') ?>
    </a>
    <a class="cat-btn<?= $topTag==='couples'&&!$subSlug?' active':'' ?>" href="/couples/">
      <span class="cat-dot" aria-hidden="true"></span><?= t('nav_couples','Couples') ?>
    </a>
    <a class="cat-btn<?= $topTag==='trans'&&!$subSlug?' active':'' ?>" href="/trans/">
      <span class="cat-dot" aria-hidden="true"></span><?= t('nav_trans','Trans') ?>
    </a>
  </nav>
</header>

<?php
$sidebarSlugGroups = [
    'girls' => [
        'Age'       => ['teens','young','milfs','mature','grannies'],
        'Stream'    => ['hd','vr','lovense','mobile'],
        'Ethnicity' => ['arab','asian','ebony','indian','latin','mixed','white','russian','ukrainian','colombian','japanese','korean','thai','chinese','pinay'],
        'Body Type' => ['petite','athletic','curvy','bbw'],
        'Hair'      => ['blondes','black-hair','brunettes','redheads','colorful'],
        'Popular'   => ['big-tits','big-ass','small-tits','anal','squirt','blowjob','deepthroat','masturbation','foot-fetish','outdoor','hairy','fisting','pregnant','lesbians','tattoos','cosplay'],
    ],
    'men' => [
        'Age'       => ['teens','young','mature'],
        'Stream'    => ['hd','vr','lovense','mobile'],
        'Ethnicity' => ['asian','ebony','latin','russian','indian','arab','white'],
        'Type'      => ['bears','bbw'],
        'Hair'      => ['blondes','brunettes','black-hair'],
        'Popular'   => ['big-cocks','anal','blowjob','masturbation','tattoos'],
    ],
    'couples' => [
        'Age'       => ['teens','mature'],
        'Stream'    => ['hd','vr','lovense','mobile'],
        'Ethnicity' => ['asian','ebony','latin','russian','indian','arab','white'],
        'Type'      => ['bbw','lesbians'],
        'Popular'   => ['big-tits','anal','blowjob','squirt','masturbation'],
    ],
    'trans' => [
        'Age'       => ['teens','young','mature'],
        'Stream'    => ['hd','vr','lovense','mobile'],
        'Ethnicity' => ['asian','ebony','latin','russian','indian','arab'],
        'Type'      => ['bbw'],
        'Hair'      => ['blondes','brunettes','black-hair'],
        'Popular'   => ['big-tits','big-cocks','anal','blowjob','masturbation','tattoos'],
    ],
];
$enSidebarLabels = [
    'teens'=>'Teen 18+','young'=>'Young 22+','milfs'=>'MILF','mature'=>'Mature','grannies'=>'Granny',
    'hd'=>'HD','vr'=>'VR','lovense'=>'Lovense','mobile'=>'Mobile',
    'arab'=>'Arab','asian'=>'Asian','ebony'=>'Ebony','indian'=>'Indian','latin'=>'Latina','mixed'=>'Mixed',
    'white'=>'White','russian'=>'Russian','ukrainian'=>'Ukrainian','colombian'=>'Colombian',
    'japanese'=>'Japanese','korean'=>'Korean','thai'=>'Thai','chinese'=>'Chinese','pinay'=>'Pinay',
    'petite'=>'Petite','athletic'=>'Athletic','curvy'=>'Curvy','bbw'=>'BBW',
    'blondes'=>'Blonde','black-hair'=>'Black','brunettes'=>'Brunette','redheads'=>'Redhead','colorful'=>'Colorful',
    'big-tits'=>'Big Tits','big-ass'=>'Big Ass','small-tits'=>'Small Tits','anal'=>'Anal','squirt'=>'Squirt',
    'blowjob'=>'Blowjob','deepthroat'=>'Deepthroat','masturbation'=>'Masturbation','foot-fetish'=>'Foot Fetish',
    'outdoor'=>'Outdoor','hairy'=>'Hairy','fisting'=>'Fisting','pregnant'=>'Pregnant','lesbians'=>'Lesbian',
    'tattoos'=>'Tattooed','cosplay'=>'Cosplay','big-cocks'=>'Big Cocks','bears'=>'Bears',
];
$groupTitleLabels = [
    'Age'       => t('sb_age','Age'),
    'Stream'    => 'Stream',
    'Ethnicity' => t('sb_ethnicity','Ethnicity'),
    'Body Type' => t('sb_body','Body Type'),
    'Hair'      => t('sb_hair','Hair'),
    'Popular'   => t('sb_popular','Popular'),
    'Type'      => t('sb_type','Type'),
];

$rawGroups = $sidebarSlugGroups[$topTag] ?? $sidebarSlugGroups['girls'];
$groups = [];
foreach ($rawGroups as $gTitle => $slugs) {
    $displayTitle = $groupTitleLabels[$gTitle] ?? $gTitle;
    $items = [];
    foreach ($slugs as $slug) {
        $items[$slug] = subLabel($slug);
    }
    $groups[$displayTitle] = $items;
}
?>

<div class="page-wrap">
<aside class="sidebar" id="sidebar" aria-label="Browse categories">
<?php foreach ($groups as $groupTitle => $items): ?>
  <section class="sb-group">
    <div class="sb-title"><?= $groupTitle ?></div>
    <?php foreach ($items as $slug => $label):
        $href    = '/' . $topTag . '/' . $slug . '/';
        $active  = ($tag === $topTag . '/' . $slug) ? ' active' : '';
    ?>
    <a class="sb-link<?= $active ?>" href="<?= $href ?>"><?= $label ?></a>
    <?php endforeach; ?>
  </section>
<?php endforeach; ?>
</aside>
<div class="sidebar-overlay" id="sidebarOverlay"></div>

<div class="main-area">
<div class="filters-bar" role="toolbar" aria-label="Filter models">
  <div class="filters-inner">
    <button class="country-btn" id="countryBtn" onclick="openCountryModal()" aria-label="Filter by country">
      <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
      <?= t('filter_countries','Countries') ?><span class="c-badge" id="countryBadge" style="display:none"></span>
    </button>
    <select class="sort-sel" id="sortSel" aria-label="Sort models">
      <option value="rating"><?= t('sort_top','Top Rated') ?></option>
      <option value="viewers"><?= t('filter_sort_viewers','Most Viewers') ?></option>
      <option value="favorites"><?= t('sort_favorites','Most Favorites') ?></option>
      <option value="new"><?= t('sort_newest','Newest') ?></option>
    </select>
  </div>
</div>

<main class="site-main" id="main" role="main">
  <div class="stats-row" aria-live="polite">
    <div class="live-badge">
      <span class="live-dot" aria-hidden="true"></span>
      <span id="onlineCount"><?= t('loading','Loading…') ?></span>
    </div>
  </div>

  <h1 style="font-size:18px;font-weight:700;margin:12px 0 14px;color:var(--text)"><?= h($heading) ?></h1>

  <section aria-label="Live cam models">
    <div class="model-grid" id="grid"></div>
  </section>
</main>

<?php if ($subSlug): ?>
<div class="seo-wrap">
  <?php if ($isDE): ?>
    <?= getSubSeoBlockDE($topTag, $subSlug, $subLabel, $topCats[$topTag] ?? ucfirst($topTag)) ?>
  <?php else: ?>
    <?= getSubSeoBlock($topTag, $subSlug, $subLabel, $topCats[$topTag] ?? ucfirst($topTag)) ?>
  <?php endif; ?>
</div>
<?php elseif (getSeoBlock($topTag) !== ''): ?>
<div class="seo-wrap">
  <?= getSeoBlock($topTag) ?>
</div>
<?php endif; ?>

</div><!-- /main-area -->
</div><!-- /page-wrap -->

<!-- ===== FOOTER ===== -->
<footer class="site-footer" role="contentinfo">
  <div class="footer-glow"></div>
  <div class="footer-inner">

    <?php
    // Определение текущего языка по subdomain
    $__host = $_SERVER['HTTP_HOST'] ?? '';
    $__sub = '';
    if (preg_match('/^([a-z]+)\.sex-videochat\.info$/', $__host, $__m)) {
        $__sub = $__m[1];
    }
    $__currentLang = match($__sub) {
        'de' => 'de', 'fr' => 'fr', 'es' => 'es', 'it' => 'it',
        'pt' => 'pt', 'jp' => 'ja', 'cn' => 'zh', 'kr' => 'ko', 'in' => 'hi',
        default => 'en',
    };
    $__langActive = fn($code) => $__currentLang === $code ? ' active' : '';
    ?>

    <!-- ROW 1: Logo + Description + Socials -->
    <div class="footer-top">
      <a href="/" class="footer-logo" aria-label="Home">
        <span class="footer-logo-icon">
          <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path d="M12 2C9 2 6 5 6 9C6 14.5 9.5 20 12 21.5C14.5 20 18 14.5 18 9C18 5 15 2 12 2Z" fill="#ff3d7f"/>
            <path d="M12 2C12 2 10.5 3.5 10.5 5C10.5 5 11.2 4.2 12 4.2C12.8 4.2 13.5 5 13.5 5C13.5 3.5 12 2 12 2Z" fill="#2a0a15"/>
            <circle cx="9.5" cy="10" r="0.9" fill="#fff" opacity="0.5"/>
            <circle cx="14.2" cy="11.5" r="0.9" fill="#fff" opacity="0.5"/>
            <circle cx="12" cy="15.5" r="0.9" fill="#fff" opacity="0.5"/>
          </svg>
        </span>
        <span class="footer-logo-text">Sex-videochat<span class="logo-tld">.info</span></span>
      </a>
      <p class="footer-tagline">Free live webcam shows with thousands of models streaming 24/7. HD quality, no registration required.</p>
      <div class="footer-socials">
        <a href="#" class="social-btn" aria-label="Twitter"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg></a>
        <a href="#" class="social-btn" aria-label="Instagram"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="20" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1" fill="currentColor"/></svg></a>
        <a href="#" class="social-btn" aria-label="Reddit"><svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.701zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.991a3.234 3.234 0 0 0 2.723 0 .263.263 0 0 1 .346.1.263.263 0 0 1-.1.347 3.756 3.756 0 0 1-3.212 0 .262.262 0 0 1-.1-.347.263.263 0 0 1 .347-.1z"/></svg></a>
      </div>
    </div>

    <!-- ROW 2: Languages (теперь ПОД соцсетями) -->
    <div class="footer-langs">
      <div class="lang-title">🌐 Languages</div>
      <div class="lang-grid">
        <a href="https://sex-videochat.info/" class="lang-link<?= $__langActive('en') ?>">🇬🇧 English</a>
        <a href="https://de.sex-videochat.info/" class="lang-link<?= $__langActive('de') ?>">🇩🇪 Deutsch</a>
        <a href="https://fr.sex-videochat.info/" class="lang-link<?= $__langActive('fr') ?>">🇫🇷 Français</a>
        <a href="https://es.sex-videochat.info/" class="lang-link<?= $__langActive('es') ?>">🇪🇸 Español</a>
        <a href="https://it.sex-videochat.info/" class="lang-link<?= $__langActive('it') ?>">🇮🇹 Italiano</a>
        <a href="https://pt.sex-videochat.info/" class="lang-link<?= $__langActive('pt') ?>">🇵🇹 Português</a>
        <a href="https://jp.sex-videochat.info/" class="lang-link<?= $__langActive('ja') ?>">🇯🇵 日本語</a>
        <a href="https://cn.sex-videochat.info/" class="lang-link<?= $__langActive('zh') ?>">🇨🇳 中国人</a>
        <a href="https://kr.sex-videochat.info/" class="lang-link<?= $__langActive('ko') ?>">🇰🇷 한국인</a>
        <a href="https://in.sex-videochat.info/" class="lang-link<?= $__langActive('hi') ?>">🇮🇳 हिंदी</a>
      </div>
    </div>

    <!-- ROW 3: 4 columns -->
    <div class="footer-cols">
      <div class="footer-col">
        <h4 class="footer-col-title">Categories</h4>
        <a href="/">Girls</a>
        <a href="/men/">Guys</a>
        <a href="/couples/">Couples</a>
        <a href="/trans/">Trans</a>
        <a href="/girls/hd/">HD Cams</a>
        <a href="/girls/vr/">VR Cams</a>
      </div>
      <div class="footer-col">
        <h4 class="footer-col-title">Popular</h4>
        <a href="/girls/teens/">Teen 18+</a>
        <a href="/girls/milfs/">MILF</a>
        <a href="/girls/asian/">Asian</a>
        <a href="/girls/latin/">Latina</a>
        <a href="/girls/russian/">Russian</a>
        <a href="/girls/bbw/">BBW</a>
      </div>
      <div class="footer-col">
        <h4 class="footer-col-title">Information</h4>
        <a href="/privacy">Privacy Policy</a>
        <a href="/terms">Terms & Conditions</a>
        <a href="/2257">2257</a>
        <a href="/dmca">Profile Removal & DMCA</a>
        <a href="/age-verification">Age Verification</a>
        <a href="/contact">Contact</a>
      </div>
      <div class="footer-col">
        <h4 class="footer-col-title">Support</h4>
        <a href="/blog">Blog</a>
        <a href="/sitemap.xml">Sitemap</a>
        <a href="/models">Models Wanted</a>
        <a href="/affiliates">Affiliates</a>
        <a href="/faq">FAQ</a>
      </div>
    </div>

    <!-- Divider -->
    <div class="footer-divider"></div>

    <!-- ROW 4: Bottom (18+ + Copyright) -->
    <div class="footer-bottom">
      <div class="footer-18">
        <span class="age-badge">18+</span>
        <p class="age-text">This website contains age-restricted materials. By entering, you confirm you are at least 18 years old. All models were 18+ at the time of depiction.</p>
      </div>
      <div class="footer-legal">
        <span>© <span id="yr"></span> sex-videochat.info. All Rights Reserved.</span>
      </div>
    </div>

  </div>
</footer>


<div class="toast-stack" id="toasts" aria-live="assertive"></div>

<!-- Country Filter Modal -->
<?php require __DIR__ . '/_country_modal.php'; ?>

<script>
const I18N = {
  modelsOnline: '<?= t('models_online','models online') ?>',
  loadMore:     '<?= t('load_more','Load More') ?>',
  noModels:     '<?= t('no_models_title','No Models Found') ?>',
  noModelsMsg:  '<?= t('no_models_msg','No models match your filters. Try changing the category or removing filters.') ?>',
  loadError:    '<?= t('load_error','Failed to load models. Please try again later.') ?>',
};
const CFG = {
  userId:  '492b59a9925d01876c059022ef32fa6f9949ef373e4179aa08008786798f6032',
  apiKey:  '22f4ea13b6dd0a08a0d9',
  siteUrl: '<?= $_siteUrl ?>',
  LIMIT:   100,
  PAGE:    50,
};

const S = {
  models: [],
  shown:  [],
  visible: CFG.PAGE,
  tag:    '<?= addslashes($tag) ?>',
  filters: new Set(),
  params:  {},
  sort:   'rating',
  query:  '',
  lastFetch: null,
  userCountry: null,
  userLang: (navigator.language||'en').split('-')[0],
  countries: [],
  langs: [],
};

function isBlocked(m) {
  if (!m.geobans) return false;
  const { blockedCountries=[], blockedLanguages=[] } = m.geobans;
  if (S.userCountry && blockedCountries.includes(S.userCountry)) return true;
  if (S.userLang   && blockedLanguages.includes(S.userLang))    return true;
  return false;
}

async function fetchModels() {
  const baseTag = S.tag.split('/')[0];
  const ep = new URLSearchParams({ userId: CFG.userId, tag: baseTag, limit: 9999 });
  const url = `/api.php?_ep=ext&${ep}`;
  const r = await fetch(url, { headers: { 'Authorization': 'Bearer ' + CFG.apiKey } });
  if (!r.ok) throw new Error('API ' + r.status);
  const d = await r.json();
  return Array.isArray(d) ? d : (d.models || d.data || []);
}

const LC_TTL = 30 * 60 * 1000;
function lcGet(tag) {
  try {
    const raw = localStorage.getItem('sc_v1_' + tag);
    if (!raw) return null;
    const { ts, data } = JSON.parse(raw);
    return Date.now() - ts < LC_TTL ? data : null;
  } catch { return null; }
}
function lcSet(tag, data) {
  try { localStorage.setItem('sc_v1_' + tag, JSON.stringify({ ts: Date.now(), data })); } catch {}
}

async function load() {
  const cacheTag = S.tag.split('/')[0];
  const cached = lcGet(cacheTag);
  if (cached && cached.length) {
    S.models = cached;
    applyAndRender();
    document.getElementById('onlineCount').textContent = S.shown.length.toLocaleString() + ' ' + I18N.modelsOnline;
  }
  try {
    const fresh = await fetchModels();
    S.models = fresh;
    lcSet(cacheTag, fresh);
    S.lastFetch = Date.now();
    applyAndRender();
    document.getElementById('onlineCount').textContent = S.shown.length.toLocaleString() + ' ' + I18N.modelsOnline;
  } catch(e) {
    if (!cached || !cached.length) toast(I18N.loadError, 'err');
  }
}

function applyAndRender() {
  let list = S.models.filter(m => !isBlocked(m));

  if (S.tag.includes('/')) {
    list = list.filter(m => Array.isArray(m.tags) && m.tags.includes(S.tag));
  }

  if (S.countries.length || S.langs.length) {
    list = list.filter(m => {
      const cc = (m.modelsCountry || '').toLowerCase();
      const ml = m.languages || [];
      return S.countries.includes(cc) || S.langs.some(l => ml.includes(l));
    });
  }

  if (S.filters.has('broadcastHD'))     list = list.filter(m => m.broadcastHD);
  if (S.filters.has('broadcastVR'))     list = list.filter(m => m.broadcastVR);
  if (S.filters.has('isNew'))           list = list.filter(m => m.isNew);
  if (S.filters.has('goalEnabled'))     list = list.filter(m => m.goalMessage || (m.neededForGoal||0) > 0);
  if (S.filters.has('broadcastMobile')) list = list.filter(m => m.broadcastMobile);

  if (S.params.profileEthnicity) {
    const ethMap = { ethnicityAsian:['asian'], ethnicityEbony:['ebony'], ethnicityLatino:['latin','latino'], ethnicityWhite:['white'], ethnicityRussian:['russian'] };
    const slugs = ethMap[S.params.profileEthnicity] || [];
    if (slugs.length) list = list.filter(m => (m.tags||[]).some(t => slugs.some(s => t === s || t.endsWith('/'+s) || t.includes('/'+s+'-'))));
  }
  if (S.params.profileSpecifics) {
    const specMap = { specificsBigTits:['big-boobs','big-tits','bigboobs','busty'], specificsBigAss:['big-ass','bigass','bubble'], specificsTattoos:['tattoo','tattooed'] };
    const slugs = specMap[S.params.profileSpecifics] || [];
    if (slugs.length) list = list.filter(m => (m.tags||[]).some(t => slugs.some(s => t.includes(s))));
  }

  if (S.query) {
    const q = S.query.toLowerCase();
    list = list.filter(m => (m.username||'').toLowerCase().includes(q) || (m.tags||[]).some(t => t.toLowerCase().includes(q)));
  }

  if (S.sort === 'viewers')   list.sort((a,b) => (b.viewersCount||0)-(a.viewersCount||0));
  if (S.sort === 'favorites') list.sort((a,b) => (b.favoritedCount||0)-(a.favoritedCount||0));
  if (S.sort === 'new')       list.sort((a,b) => (b.isNew?1:0)-(a.isNew?1:0));

  S.shown   = list;
  S.visible = CFG.PAGE;
  document.getElementById('onlineCount').textContent = list.length.toLocaleString() + ' ' + I18N.modelsOnline;
  renderGrid();
}

function renderGrid() {
  const g = document.getElementById('grid');
  const list = S.shown;
  if (!list.length) { g.innerHTML = `<div class="empty"><h3>${I18N.noModels}</h3><p>${I18N.noModelsMsg}</p></div>`; return; }
  const slice = list.slice(0, S.visible);
  const remaining = list.length - S.visible;
  g.innerHTML = slice.map(m => cardHtml(m)).join('') + (remaining > 0
    ? `<div class="load-more-wrap" id="loadMoreWrap"><button class="load-more-btn" onclick="loadMore()">${I18N.loadMore}</button></div>`
    : '');
}

function loadMore() {
  S.visible += CFG.PAGE;
  const list = S.shown;
  const g = document.getElementById('grid');
  document.getElementById('loadMoreWrap')?.remove();
  list.slice(S.visible - CFG.PAGE, S.visible).forEach(m => g.insertAdjacentHTML('beforeend', cardHtml(m)));
  if (list.length - S.visible > 0)
    g.insertAdjacentHTML('beforeend', `<div class="load-more-wrap" id="loadMoreWrap"><button class="load-more-btn" onclick="loadMore()">${I18N.loadMore}</button></div>`);
}

function cardHtml(m) {
  const img = m.snapshotUrl || m.popularSnapshotUrl || m.previewUrlThumbSmall || m.avatarUrl || '';
  const pct = m.neededForGoal > 0 ? Math.min(100, Math.round((m.earnedForGoal||0) / m.neededForGoal * 100)) : 0;
  const tags = (m.tags||[]).filter(t=>!['girls','men','trans','couples'].includes(t)).slice(0,3);
  const status = m.status || 'public';
  return `<a class="model-card" href="/model/${enc(m.username)}" data-u="${enc(m.username)}" aria-label="${esc(m.username)} live webcam">
    <div class="card-thumb">
      <img class="card-img" src="${esc(img)}" alt="${esc(m.username)} live cam" loading="lazy" decoding="async" width="320" height="240"
        onerror="this.src='data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 80 80%22%3E%3Crect width=%2280%22 height=%2280%22 fill=%22%23181820%22/%3E%3C/svg%3E'">
      <div class="card-overlay" aria-hidden="true"></div>
      <div class="play-icon" aria-hidden="true"><svg viewBox="0 0 48 48" fill="none"><circle cx="24" cy="24" r="24" fill="rgba(0,0,0,.55)"/><polygon points="19,15 36,24 19,33" fill="white"/></svg></div>
      <div class="card-badges" aria-hidden="true">
        ${status!=='public'?`<span class="badge ${status==='private'||status==='p2p'?'b-private':'b-group'}">${status==='groupShow'?'GROUP':'PRIVATE'}</span>`:''}
        ${m.broadcastHD?'<span class="badge b-hd">HD</span>':''}
        ${m.broadcastVR?'<span class="badge b-vr">VR</span>':''}
        ${m.isNew?'<span class="badge b-new">NEW</span>':''}
        ${m.goalMessage||m.neededForGoal>0?'<span class="badge b-goal">GOAL</span>':''}
      </div>
      <span class="card-online" aria-hidden="true"></span>
      ${(m.viewersCount||0)>0?`<span class="card-viewers">${fmtNum(m.viewersCount)}</span>`:''}
      ${pct>0?`<div class="card-goal-bar"><div class="card-goal-fill" style="width:${pct}%"></div></div>`:''}
    </div>
    <div class="card-info">
      <div class="card-name">${esc(m.username)}</div>
      <div class="card-meta">
        ${m.modelsCountry?`<span>${flag(m.modelsCountry)} ${m.modelsCountry.toUpperCase()}</span>`:''}
        ${(m.favoritedCount||0)>0?`<span class="card-fav">♥ ${fmtNum(m.favoritedCount)}</span>`:''}
      </div>
    </div>
  </a>`;
}


function initFilters() {
  document.querySelectorAll('.chip[data-f]').forEach(c => {
    c.addEventListener('click', () => {
      const f = c.dataset.f;
      if (S.filters.has(f)) { S.filters.delete(f); c.classList.remove('on'); c.setAttribute('aria-pressed','false'); }
      else { S.filters.add(f); c.classList.add('on'); c.setAttribute('aria-pressed','true'); }
      applyAndRender();
    });
  });
  document.querySelectorAll('.chip[data-p]').forEach(c => {
    c.addEventListener('click', () => {
      const p = c.dataset.p, v = c.dataset.v;
      if (S.params[p] === v) {
        delete S.params[p]; c.classList.remove('on'); c.setAttribute('aria-pressed','false');
      } else {
        document.querySelectorAll(`.chip[data-p="${p}"]`).forEach(x => { x.classList.remove('on'); x.setAttribute('aria-pressed','false'); });
        S.params[p] = v; c.classList.add('on'); c.setAttribute('aria-pressed','true');
      }
      applyAndRender();
    });
  });
  document.getElementById('sortSel').addEventListener('change', e => { S.sort = e.target.value; applyAndRender(); });
}

function initSearch() {
  let t;
  document.getElementById('searchInput').addEventListener('input', e => {
    clearTimeout(t);
    t = setTimeout(() => { S.query = e.target.value.trim(); applyAndRender(); }, 280);
  });
}

function initGridClicks() {
  document.getElementById('grid').addEventListener('click', e => {
    const card = e.target.closest('.model-card[data-u]');
    if (!card) return;
    const uname = decodeURIComponent(card.dataset.u);
    const m = S.models.find(x => x.username === uname);
    if (m) try { sessionStorage.setItem('sc_m_' + uname, JSON.stringify(m)); } catch {}
  });
}

function toast(msg, type) {
  const d = document.createElement('div');
  d.className = 'toast ' + (type||'');
  d.textContent = msg;
  document.getElementById('toasts').appendChild(d);
  setTimeout(() => d.remove(), 4500);
}

function enc(s)  { return encodeURIComponent(s||'') }
function esc(s)  { return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;') }
function fmtNum(n) { n=n||0; if(n>=1e6) return (n/1e6).toFixed(1)+'M'; if(n>=1e3) return (n/1e3).toFixed(1)+'K'; return String(n); }
function flag(code) {
  if(!code||code.length!==2) return '';
  return [...code.toUpperCase()].map(c=>String.fromCodePoint(0x1F1E6+c.charCodeAt(0)-65)).join('');
}

function openCountryModal() {
  document.getElementById('countryModal').classList.add('open');
}
function closeCountryModal() {
  document.getElementById('countryModal').classList.remove('open');
}
function clearCountries() {
  S.countries = []; S.langs = [];
  document.querySelectorAll('#countryModal input[type=checkbox]').forEach(cb => cb.checked = false);
  updateCountryBtn();
  applyAndRender();
}
function updateCountryBtn() {
  const total = S.countries.length + S.langs.length;
  const badge = document.getElementById('countryBadge');
  const btn = document.getElementById('countryBtn');
  badge.textContent = total || '';
  badge.style.display = total ? '' : 'none';
  btn.classList.toggle('on', total > 0);
}
function initCountryModal() {
  document.querySelectorAll('#countryModal input[data-cc]').forEach(cb => {
    cb.addEventListener('change', () => {
      const cc = cb.dataset.cc;
      if (cb.checked) { if (!S.countries.includes(cc)) S.countries.push(cc); }
      else S.countries = S.countries.filter(c => c !== cc);
      updateCountryBtn(); applyAndRender();
    });
  });
  document.querySelectorAll('#countryModal input[data-lang]').forEach(cb => {
    cb.addEventListener('change', () => {
      const l = cb.dataset.lang;
      if (cb.checked) { if (!S.langs.includes(l)) S.langs.push(l); }
      else S.langs = S.langs.filter(x => x !== l);
      updateCountryBtn(); applyAndRender();
    });
  });
  document.getElementById('countryModal').addEventListener('click', e => {
    if (e.target === e.currentTarget) closeCountryModal();
  });
  document.addEventListener('keydown', e => {
    if (e.key === 'Escape') closeCountryModal();
  });
}

async function init() {
  document.getElementById('yr').textContent = new Date().getFullYear();
  initFilters();
  initSearch();
  initGridClicks();
  initCountryModal();
  fetch('/api.php?_ep=geo', { signal: AbortSignal.timeout(3000) })
    .then(r=>r.json()).then(d=>{ S.userCountry=(d.country_code||'').toLowerCase(); }).catch(()=>{});
  await load();
}

init();

// Sidebar toggle
(function(){
  const btn = document.createElement('button');
  btn.className = 'scroll-top';
  btn.setAttribute('aria-label', 'Scroll to top');
  btn.innerHTML = '<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5"><path d="M18 15l-6-6-6 6"/></svg>';
  btn.onclick = () => window.scrollTo({ top: 0, behavior: 'smooth' });
  document.body.appendChild(btn);
  window.addEventListener('scroll', () => {
    btn.classList.toggle('visible', window.scrollY > 400);
  }, { passive: true });
})();
</script>



</body>
</html>