/* ========== KUBIKON STUDIO — стартовый экран Рублокс Studio ========== Синяя wow-палитра, glassmorphism, плавные анимации. Палитра построена вокруг логотипа A02 — синий #3357ff. */ .studio *, .studio *::before, .studio *::after { box-sizing: border-box; } .studio { /* Тёмная тема в стиле Roblox Studio: почти-чёрный фон, панели чуть светлее, белый текст, синий акцент Рублокса. */ --bg-darkest: #161616; --bg-dark: #1e1e1e; --bg-mid: #232323; --bg-light: #2a2a2a; --bg-subtle: #1c1c1c; --accent: #4f74ff; --accent-deep: #1e2da5; --accent-soft: #2a3354; --accent2: #8b5cf6; --pink: #ec4899; --gold: #f59e0b; --cyan: #06b6d4; --text: #f2f3f5; --text-dim: #b6bac4; --text-muted: #7f848f; --border: #333333; --border-soft: #2c2c2c; --border-strong: #444444; --danger: #ef4444; --success: #10b981; --warning: #f59e0b; --radius: 10px; --radius-lg: 14px; --radius-xl: 20px; --radius-2xl: 28px; --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04); --shadow: 0 1px 3px rgba(15, 23, 42, 0.06), 0 2px 6px rgba(15, 23, 42, 0.04); --shadow-md: 0 4px 16px rgba(15, 23, 42, 0.08), 0 2px 6px rgba(15, 23, 42, 0.04); --shadow-lg: 0 12px 32px rgba(15, 23, 42, 0.12), 0 6px 12px rgba(15, 23, 42, 0.06); --shadow-accent: 0 8px 24px rgba(51, 87, 255, 0.32); --gradient-brand: linear-gradient(135deg, #3357ff 0%, #1e2da5 100%); --gradient-hero: linear-gradient(135deg, #3357ff 0%, #6d28d9 50%, #ec4899 100%); --gradient-cool: linear-gradient(135deg, #06b6d4 0%, #3357ff 100%); --gradient-purple: linear-gradient(135deg, #8b5cf6 0%, #3357ff 100%); --font: "Roboto Condensed", system-ui, -apple-system, sans-serif; /* Структура: высота = ровно видимая область .wrap_page (минус 61px хедер). Внутри — flex-row. Sidebar статичный (height: 100%), main — отдельный скролл-контейнер с overflow-y: auto. Когда main докручен до низа, дальше начинает скроллить внешний .wrap_page и показывает футер. */ position: relative; display: flex; align-items: stretch; height: calc(100vh - 61px); width: 100%; max-width: 100%; background: var(--bg-darkest); color: var(--text); box-sizing: border-box; font-family: var(--font); /* Лёгкий синий «свет» в углах — на тёмном фоне чуть ярче */ background-image: radial-gradient(ellipse 600px 400px at 0% 0%, rgba(79, 116, 255, 0.10) 0%, transparent 70%), radial-gradient(ellipse 600px 400px at 100% 100%, rgba(139, 92, 246, 0.08) 0%, transparent 70%); } /* ===== Sidebar ===== Не двигается вообще: статичная колонка во всю высоту .studio. .studio высотой = видимая область .wrap_page, поэтому sidebar занимает всю видимую часть и не уходит за неё. Скроллится только .main (см. ниже). */ .sidebar { width: 240px; flex-shrink: 0; height: 100%; background: #1c1c1c; border-right: 1px solid var(--border); display: flex; flex-direction: column; z-index: 10; box-shadow: 1px 0 12px rgba(0, 0, 0, 0.3); } .sidebarHeader { padding: 20px 18px; display: flex; align-items: center; gap: 12px; border-bottom: 1px solid var(--border-soft); } /* Плашка-логотип: сам RublocsLogo рисует скруглённый квадрат (через свой проп bg) — фирменный логотип Рублокса целиком. Дополнительный фон/градиент тут не нужен. */ .sidebarLogo { width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .sidebarTitle { display: flex; flex-direction: column; line-height: 1; } .brandName { font-size: 18px; font-weight: 900; color: var(--text); letter-spacing: -0.5px; } .brandSub { font-size: 11px; color: var(--accent); font-weight: 800; text-transform: uppercase; letter-spacing: 1.4px; margin-top: 4px; } .sidebarNav { flex: 1; padding: 14px 12px; display: flex; flex-direction: column; gap: 4px; overflow-y: auto; } .navItem { display: flex; align-items: center; gap: 12px; padding: 10px 14px; background: transparent; border: none; border-radius: var(--radius); color: var(--text-dim); font-size: 14px; font-weight: 700; cursor: pointer; transition: all 160ms ease; text-align: left; width: 100%; font-family: inherit; letter-spacing: 0.1px; } .navItem:hover { background: var(--bg-light); color: var(--text); } /* Активный пункт — в Roblox Studio это просто подсветка панелью и синяя полоска слева, без яркого градиента. */ .navActive, .navActive:hover { background: var(--bg-light); color: #fff; box-shadow: inset 3px 0 0 var(--accent); } .navActive .navIcon { color: var(--accent); } .navIcon { width: 22px; display: inline-flex; align-items: center; justify-content: center; color: var(--text-muted); } .navItem:hover .navIcon { color: var(--text-dim); } /* Кнопка «Новая игра» — акцентная, синяя, наверху меню */ .navNewGame { display: flex; align-items: center; gap: 12px; padding: 11px 14px; margin-bottom: 8px; background: var(--accent); border: none; border-radius: var(--radius); color: #fff; font-size: 14px; font-weight: 800; cursor: pointer; transition: all 160ms ease; text-align: left; width: 100%; font-family: inherit; } .navNewGame:hover { background: #5d80ff; transform: translateY(-1px); } .navNewGameIco { width: 22px; display: inline-flex; align-items: center; justify-content: center; } .sidebarFooter { padding: 14px 14px 18px; border-top: 1px solid var(--border-soft); } .docsBtn { width: 100%; padding: 10px 14px; background: var(--bg-light); border: 1px solid var(--border); border-radius: var(--radius); color: var(--text); font-size: 13px; font-weight: 700; cursor: pointer; font-family: inherit; transition: all 150ms ease; } .docsBtn:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); } /* ===== Main ===== */ .main { flex: 1; min-width: 0; height: 100%; /* Внутренний скролл — sidebar остаётся неподвижным. */ overflow-y: auto; overflow-x: hidden; padding: 24px 32px 60px; width: 100%; /* Когда main докручен до низа, браузер автоматически начинает прокручивать родителя (.wrap_page) дальше — к футеру. overscroll-behavior: auto разрешает это (это значение по умолчанию, пишем явно для ясности). */ overscroll-behavior: auto; } .main > * { max-width: 1240px; margin-left: auto; margin-right: auto; } .topBar { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 28px; flex-wrap: wrap; } .pageTitle { margin: 0; font-size: 32px; font-weight: 900; color: var(--text); letter-spacing: -1px; } .pageSub { margin: 4px 0 0; font-size: 14px; color: var(--text-dim); font-weight: 500; } .topBarActions { display: flex; gap: 10px; align-items: center; } .searchBox { padding: 10px 18px; background: var(--bg-light); border: 1px solid var(--border); border-radius: 999px; color: var(--text-dim); font-size: 13px; font-weight: 600; cursor: pointer; font-family: inherit; transition: all 200ms ease; } .searchBox:hover { border-color: var(--accent); color: var(--accent); box-shadow: var(--shadow-sm); } .profileBtn { padding: 10px 18px; background: var(--gradient-brand); border: 1px solid transparent; border-radius: 999px; color: #fff; font-size: 13px; font-weight: 800; cursor: pointer; font-family: inherit; box-shadow: var(--shadow-accent); transition: all 200ms ease; } .profileBtn:hover { transform: translateY(-2px); box-shadow: 0 12px 28px rgba(51, 87, 255, 0.45); } /* ===== Hero — крупный баннер с кадром игры (как в Roblox Studio) ===== */ .hero { position: relative; border-radius: var(--radius-xl); margin-bottom: 36px; overflow: hidden; min-height: 230px; display: flex; align-items: center; border: 1px solid var(--border); box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4); } /* кадр игры на весь баннер */ .heroImg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; } /* затемнение слева — чтобы белый текст читался поверх кадра */ .heroOverlay { position: absolute; inset: 0; background: linear-gradient(100deg, rgba(8, 11, 22, 0.90) 0%, rgba(8, 11, 22, 0.66) 40%, rgba(8, 11, 22, 0.10) 70%, transparent 100%); pointer-events: none; } .heroContent { position: relative; z-index: 2; flex: 1; min-width: 280px; max-width: 560px; padding: 38px 44px; } .heroBadge { display: inline-flex; align-items: center; background: rgba(255, 255, 255, 0.16); border: 1px solid rgba(255, 255, 255, 0.30); color: #fff; padding: 5px 14px; border-radius: 999px; font-size: 11px; font-weight: 800; letter-spacing: 1.4px; text-transform: uppercase; margin-bottom: 14px; } .heroTitle { margin: 0 0 12px; font-size: 38px; line-height: 1.08; font-weight: 900; color: #fff; letter-spacing: -1px; text-shadow: 0 2px 18px rgba(0, 0, 0, 0.55); } .heroDesc { margin: 0 0 22px; font-size: 15.5px; color: rgba(255, 255, 255, 0.92); line-height: 1.55; text-shadow: 0 1px 10px rgba(0, 0, 0, 0.5); } .heroBtn { display: inline-flex; align-items: center; gap: 8px; padding: 13px 26px; background: var(--accent); border: none; border-radius: var(--radius); color: #fff; font-size: 15px; font-weight: 900; cursor: pointer; font-family: inherit; box-shadow: 0 12px 28px rgba(0, 0, 0, 0.4); transition: all 200ms ease; letter-spacing: 0.2px; } .heroBtn:hover { background: #5d80ff; transform: translateY(-2px); } @keyframes studioGradientShift { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } } /* ===== «Изучай Студию» — карточки-гайды (Discover Studio) ===== */ .guideGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; } /* Карточки — светлые, в стиле вики (белый фон, тёмный текст). */ .guideCard { background: #ffffff; border: 1px solid #e5e7eb; border-radius: var(--radius-lg); overflow: hidden; cursor: pointer; transition: border-color 180ms ease, transform 180ms ease, box-shadow 180ms ease; text-align: left; font-family: inherit; padding: 0; display: flex; flex-direction: column; } .guideCard:hover { transform: translateY(-3px); border-color: #3357ff; box-shadow: 0 14px 32px rgba(15, 23, 42, 0.16); } .guideImage { position: relative; aspect-ratio: 16 / 10; overflow: hidden; } /* превью-скриншот статьи */ .guideImg { position: relative; width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 300ms ease; } .guideCard:hover .guideImg { transform: scale(1.05); } /* запасной фон под картинкой (если скрин не загрузился) */ .guideFallback { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: rgba(255, 255, 255, 0.92); } .guideBody { padding: 14px 16px 16px; } .guideTitle { font-size: 15px; font-weight: 800; color: #0f172a; margin-bottom: 5px; } .guideDesc { font-size: 12.5px; color: #64748b; line-height: 1.5; } @keyframes studioFadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } @keyframes studioFadeInScale { from { opacity: 0; transform: scale(0.94); } to { opacity: 1; transform: scale(1); } } @keyframes studioPulseGlow { 0%, 100% { box-shadow: 0 8px 24px rgba(51, 87, 255, 0.32); } 50% { box-shadow: 0 8px 24px rgba(51, 87, 255, 0.32), 0 0 0 12px rgba(51, 87, 255, 0.08); } } @keyframes studioSpin { to { transform: rotate(360deg); } } /* ===== Sections ===== */ .section { margin-bottom: 36px; animation: studioFadeIn 400ms ease both; } .sectionHead { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 16px; gap: 12px; } .sectionTitle { margin: 0; font-size: 22px; font-weight: 800; color: var(--text); letter-spacing: -0.4px; } .sectionMore { background: transparent; border: none; color: var(--accent); font-size: 13px; font-weight: 800; cursor: pointer; font-family: inherit; padding: 6px 12px; border-radius: 999px; transition: all 150ms ease; } .sectionMore:hover { background: var(--accent-soft); } /* подпись справа от заголовка секции (как в Roblox Studio) */ .sectionSub { font-size: 13px; color: var(--text-dim); font-weight: 500; text-align: right; } /* ===== Templates ===== */ .tplGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; } .tplCard { position: relative; padding: 0; background: var(--bg-mid); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; cursor: pointer; transition: all 280ms cubic-bezier(0.34, 1.56, 0.64, 1); font-family: inherit; box-shadow: var(--shadow); } .tplCard:hover:not(:disabled) { transform: translateY(-6px); border-color: var(--accent); box-shadow: var(--shadow-lg), 0 0 0 1px var(--accent); } .tplCard:disabled { cursor: not-allowed; opacity: 0.85; } .tplImageWrap { position: relative; width: 100%; aspect-ratio: 16 / 11; overflow: hidden; background: var(--bg-light); } .tplImage { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 2; transition: transform 600ms cubic-bezier(0.2, 0.8, 0.4, 1); } .tplCard:hover .tplImage { transform: scale(1.08); } .tplFallback { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 1; } .tplFallbackEmoji { font-size: 64px; opacity: 0.8; filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.30)); } .tplOverlay { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(15, 23, 42, 0) 30%, rgba(15, 23, 42, 0.55) 70%, rgba(15, 23, 42, 0.85) 100%); z-index: 3; pointer-events: none; } .tplContent { position: absolute; left: 14px; right: 14px; bottom: 12px; z-index: 4; color: #fff; } .tplBadge { width: 36px; height: 36px; border-radius: 10px; background: rgba(255, 255, 255, 0.20); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.30); display: inline-flex; align-items: center; justify-content: center; font-size: 18px; margin-bottom: 6px; } .tplTitle { font-size: 17px; font-weight: 800; letter-spacing: -0.2px; margin-bottom: 2px; text-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); } .tplDesc { font-size: 12px; opacity: 0.92; font-weight: 600; line-height: 1.35; text-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); } .tplCta { position: absolute; inset: 0; z-index: 5; display: flex; align-items: center; justify-content: center; background: rgba(51, 87, 255, 0.86); backdrop-filter: blur(4px); color: #fff; font-size: 16px; font-weight: 800; opacity: 0; transition: opacity 220ms ease; } .tplCard:hover .tplCta { opacity: 1; } .tplLoading { position: absolute; inset: 0; z-index: 6; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; background: rgba(15, 23, 42, 0.78); color: #fff; font-weight: 800; } .tplLoadingSpinner { width: 32px; height: 32px; border: 3px solid rgba(255, 255, 255, 0.2); border-top-color: #fff; border-radius: 50%; animation: studioSpin 0.9s linear infinite; } /* ===== Project / template cards (универсальные) ===== */ .templatesGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; } /* Карточки игр — светлые, в стиле вики (белый фон, тёмный текст). */ .templateCard { position: relative; background: #ffffff; border: 1px solid #e5e7eb; border-radius: var(--radius-lg); overflow: hidden; cursor: pointer; transition: all 280ms cubic-bezier(0.34, 1.56, 0.64, 1); text-align: left; display: flex; flex-direction: column; box-shadow: var(--shadow); font-family: inherit; color: var(--text); } .templateCard:hover { transform: translateY(-6px); border-color: #3357ff; box-shadow: 0 16px 36px rgba(15, 23, 42, 0.16); } .templatePreview { position: relative; width: 100%; aspect-ratio: 4 / 3; overflow: hidden; background: linear-gradient(135deg, var(--accent) 0%, var(--accent-deep) 100%) !important; display: flex; align-items: center; justify-content: center; } .templatePreview img { width: 100%; height: 100%; object-fit: cover; transition: transform 600ms cubic-bezier(0.2, 0.8, 0.4, 1); } .templateCard:hover .templatePreview img { transform: scale(1.08); } .templateEmoji { font-size: 56px; color: #fff; filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.30)); } .templateBody { padding: 12px 14px 14px; } .templateTitle { font-size: 15px; font-weight: 800; color: #0f172a; margin-bottom: 4px; letter-spacing: -0.2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .templateDesc { font-size: 12px; color: #64748b; font-weight: 600; } /* ===== Empty states ===== */ .emptyState { padding: 56px 32px; text-align: center; background: var(--bg-mid); border: 1px dashed var(--border-strong); border-radius: var(--radius-xl); animation: studioFadeInScale 360ms cubic-bezier(0.34, 1.56, 0.64, 1); } .emptyEmoji { font-size: 64px; margin-bottom: 12px; animation: studioFloat 4s ease-in-out infinite; display: inline-block; } .emptyTitle { font-size: 20px; font-weight: 800; color: var(--text); margin-bottom: 6px; letter-spacing: -0.3px; } .emptyDesc { font-size: 14px; color: var(--text-dim); margin-bottom: 20px; } .emptyBtn { padding: 12px 24px; background: var(--gradient-brand); color: #fff; border: none; border-radius: var(--radius); font-size: 14px; font-weight: 800; cursor: pointer; font-family: inherit; box-shadow: var(--shadow-accent); transition: all 220ms cubic-bezier(0.34, 1.56, 0.64, 1); letter-spacing: 0.2px; } .emptyBtn:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 12px 28px rgba(51, 87, 255, 0.45); } .emptyStateSmall { padding: 28px; text-align: center; color: var(--text-muted); font-size: 14px; font-weight: 600; } /* ===== Footer block ===== */ .footerBlock { margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--border-soft); } .footerInfo { font-size: 12px; color: var(--text-muted); text-align: center; font-weight: 600; letter-spacing: 0.4px; } /* ===== Modal — подтверждение удаления ===== */ .modalBackdrop { position: fixed; inset: 0; z-index: 2200; background: rgba(15, 23, 42, 0.55); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); display: flex; align-items: center; justify-content: center; padding: 20px; animation: studioFadeIn 200ms ease; } .modalCard { background: var(--bg-mid); border: 1px solid var(--border); border-radius: var(--radius-2xl); padding: 32px 28px; width: 100%; max-width: 440px; text-align: center; color: var(--text); box-shadow: var(--shadow-lg), 0 0 0 1px rgba(51, 87, 255, 0.06); animation: studioFadeInScale 280ms cubic-bezier(0.34, 1.56, 0.64, 1); font-family: inherit; } .modalIcon { width: 76px; height: 76px; margin: 0 auto 16px; border-radius: 50%; background: linear-gradient(135deg, #ff6f7a 0%, #c0303f 100%); display: flex; align-items: center; justify-content: center; font-size: 36px; box-shadow: 0 12px 28px rgba(239, 68, 68, 0.36), 0 0 0 8px rgba(239, 68, 68, 0.12); animation: studioFloat 3.6s ease-in-out infinite; } .modalTitle { font-size: 22px; font-weight: 800; color: var(--text); margin-bottom: 8px; letter-spacing: -0.4px; } .modalText { font-size: 14px; color: var(--text-dim); margin-bottom: 24px; line-height: 1.55; } .modalActions { display: flex; gap: 10px; justify-content: center; } .modalCancelBtn { padding: 10px 22px; background: var(--bg-light); border: 1px solid var(--border); color: var(--text); border-radius: var(--radius); font-size: 14px; font-weight: 700; cursor: pointer; font-family: inherit; transition: all 150ms ease; } .modalCancelBtn:hover:not(:disabled) { background: var(--bg-darkest); border-color: var(--border-strong); } .modalCancelBtn:disabled { opacity: 0.5; cursor: not-allowed; } .modalDeleteBtn { padding: 10px 22px; background: linear-gradient(135deg, #ff6f7a 0%, #c0303f 100%); border: 1px solid transparent; color: #fff; border-radius: var(--radius); font-size: 14px; font-weight: 800; cursor: pointer; font-family: inherit; box-shadow: 0 6px 16px rgba(239, 68, 68, 0.32); transition: all 200ms cubic-bezier(0.34, 1.56, 0.64, 1); } .modalDeleteBtn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 12px 28px rgba(239, 68, 68, 0.45); } .modalDeleteBtn:disabled { opacity: 0.6; cursor: not-allowed; } /* ===== Адаптив ===== */ @media (max-width: 900px) { .studio { flex-direction: column; } .sidebar { position: relative; top: auto; height: auto; width: 100%; flex-direction: row; align-items: center; padding: 8px 14px; gap: 8px; overflow-x: auto; } .sidebarHeader { padding: 6px 10px; border: none; } .sidebarNav { flex-direction: row; flex: 1; padding: 0; overflow-y: visible; } .sidebarFooter { display: none; } .main { padding: 16px 18px 40px; } .pageTitle { font-size: 24px; } .heroTitle { font-size: 28px; } .hero { padding: 28px 24px; flex-direction: column; } .heroVisual { width: 160px; height: 160px; } }