/*
  SnapDub UI layer (redesign step 1, 2026-10-29) - see docs/redesign-plan-2026-10.md.

  ONE set of scales and components every page is rebuilt from. Loaded after application.css and
  namespaced `ui-` on purpose: nothing here touches a page until that page is moved onto it, and
  the old classes are deleted page by page as they go (no second design system living forever).

  Colours are NOT redefined: the surfaces, ink, brand and status tokens in application.css already
  carry light and dark through light-dark(). This file adds the scales they never had.

  Live reference of everything below: /design (god accounts).
*/

:root {
  /* Type: 6 sizes, 3 weights. 16px is also the phone input size (iOS zooms below it). */
  --text-xs: 12px;
  --text-sm: 13px;
  --text-md: 14px;
  --text-lg: 16px;
  --text-xl: 20px;
  --text-2xl: 28px;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --leading-tight: 1.25;
  --leading-normal: 1.5;

  /* Spacing */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  /* Radius */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-full: 999px;

  /* Elevation: only things that float get a shadow; cards are filled, not lifted. */
  --elev-popover: 0 8px 24px -8px rgba(24, 24, 27, 0.18), 0 2px 6px -2px rgba(24, 24, 27, 0.08);
  --elev-dialog: 0 24px 64px -16px rgba(24, 24, 27, 0.32);

  /* Motion */
  --dur-press: 120ms;
  --dur-enter: 200ms;
  --dur-exit: 160ms;
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);

  /* Touch */
  --tap: 44px;

  /* The app frame behind the inset content surface: a step darker than the page. */
  --frame: light-dark(#ededef, #0a0a0c);
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-press: 0ms; --dur-enter: 0ms; --dur-exit: 0ms; }
}

/* ---------------------------------------------------------------- Layout primitives */
/* Two ways of putting things next to each other, so pages stop writing their own flex rows. */
.ui-stack { display: flex; flex-direction: column; gap: var(--space-4); }
.ui-stack--sm { gap: var(--space-2); }
.ui-stack--lg { gap: var(--space-6); }
.ui-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.ui-section-title { margin: 0; font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--ink); }
.ui-muted { color: var(--ink-3); font-size: var(--text-sm); }

/* ---------------------------------------------------------------- Page header */
.ui-page-header { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-3) var(--space-4); margin-bottom: var(--space-5); }
.ui-page-header__text { flex: 1 1 280px; min-width: 0; }
.ui-page-header__eyebrow { font-size: var(--text-sm); color: var(--ink-3); }
.ui-page-header__title { margin: var(--space-1) 0 0; font-size: var(--text-xl); font-weight: var(--weight-semibold); line-height: var(--leading-tight); color: var(--ink); }
.ui-page-header__meta { margin-top: var(--space-1); font-size: var(--text-md); color: var(--ink-2); }
.ui-page-header__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
@media (min-width: 768px) { .ui-page-header__title { font-size: var(--text-2xl); } }

/* ---------------------------------------------------------------- Buttons */
.ui-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: 40px; padding: 0 var(--space-4); border: 0; border-radius: var(--radius-full);
  font: inherit; font-size: var(--text-md); font-weight: var(--weight-semibold); line-height: 1;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  background: var(--surface-2); color: var(--ink);
  transition: background var(--dur-press) var(--ease-out), transform var(--dur-press) var(--ease-out);
}
.ui-btn:hover { background: var(--line-strong); }
.ui-btn:active { transform: scale(0.97); }
.ui-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.ui-btn[disabled], .ui-btn[aria-disabled="true"] { opacity: 0.5; pointer-events: none; }
.ui-btn--primary { background: var(--primary); color: #ffffff; }
.ui-btn--primary:hover { background: var(--primary-hover); }
.ui-btn--dark { background: var(--inverse); color: var(--inverse-ink); }
.ui-btn--dark:hover { background: var(--inverse); opacity: 0.88; }
.ui-btn--ghost { background: transparent; color: var(--ink-soft); }
.ui-btn--ghost:hover { background: var(--surface-2); }
.ui-btn--danger { background: var(--st-red-bg); color: var(--st-red); }
.ui-btn--danger:hover { background: var(--st-red-line); }
.ui-btn--sm { height: 32px; padding: 0 var(--space-3); font-size: var(--text-sm); }
.ui-btn--lg { height: 48px; padding: 0 var(--space-5); font-size: var(--text-lg); }
.ui-btn--block { width: 100%; }
.ui-btn--icon { width: 40px; padding: 0; }
.ui-btn--icon.ui-btn--sm { width: 32px; }
@media (max-width: 767px) {
  /* Thumbs, not cursors: every button reaches the comfortable tap size on a phone. */
  .ui-btn { min-height: var(--tap); }
  .ui-btn--icon { min-width: var(--tap); }
  .ui-chip { height: 40px; padding: 0 var(--space-4); }
  .ui-tile__menu { width: var(--tap); height: var(--tap); }
}

/* ---------------------------------------------------------------- Cards and surfaces */
.ui-card { background: var(--surface); border-radius: var(--radius-lg); padding: var(--space-4); }
.ui-card--muted { background: var(--surface-2); }
.ui-card.ui-card--flush { padding: 0; overflow: hidden; }
.ui-card__title { margin: 0 0 var(--space-2); font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--ink); }
.ui-card__text { margin: 0; font-size: var(--text-md); color: var(--ink-2); line-height: var(--leading-normal); }
@media (min-width: 768px) { .ui-card { padding: var(--space-5); } }

/* ---------------------------------------------------------------- Chips and badges */
.ui-chip {
  display: inline-flex; align-items: center; gap: var(--space-1); height: 32px; padding: 0 var(--space-3);
  border: 0; border-radius: var(--radius-full); background: var(--surface-2); color: var(--ink-soft);
  font: inherit; font-size: var(--text-sm); font-weight: var(--weight-medium); text-decoration: none; cursor: pointer;
  transition: background var(--dur-press) var(--ease-out);
}
.ui-chip:hover { background: var(--line-strong); }
.ui-chip[aria-pressed="true"], .ui-chip--active { background: var(--inverse); color: var(--inverse-ink); }
.ui-badge {
  display: inline-flex; align-items: center; height: 22px; padding: 0 var(--space-2); border-radius: var(--radius-full);
  font-size: var(--text-xs); font-weight: var(--weight-semibold); background: var(--surface-2); color: var(--ink-soft);
}
.ui-badge--brand { background: var(--primary-tint); color: var(--primary); }
.ui-badge--green { background: var(--st-green-bg); color: var(--st-green); }
.ui-badge--blue { background: var(--st-blue-bg); color: var(--st-blue); }
.ui-badge--red { background: var(--st-red-bg); color: var(--st-red); }
.ui-badge--on-media { background: #ffffff; color: #18181b; }

/* ---------------------------------------------------------------- List rows */
.ui-list { display: flex; flex-direction: column; background: var(--surface-2); border-radius: var(--radius-lg); overflow: hidden; }
.ui-row {
  display: flex; align-items: center; gap: var(--space-3); min-height: 52px; padding: var(--space-2) var(--space-4);
  font-size: var(--text-md); color: var(--ink); text-decoration: none; background: transparent; border: 0; width: 100%;
  font-family: inherit; text-align: left; cursor: pointer;
  transition: background var(--dur-press) var(--ease-out);
}
/* A line between visible rows only: rows can be hidden (shown by a controller), and a button_to row
   arrives wrapped in its own form, so this counts siblings rather than adjacent .ui-rows. */
.ui-list > :not([hidden]) ~ :not([hidden]) { border-top: 1px solid var(--line); }
.ui-list__form { margin: 0; }
.ui-row[hidden] { display: none; }
.ui-row:hover { background: var(--line); }
.ui-row__icon { flex: none; color: var(--ink-3); display: inline-flex; }
.ui-row__body { flex: 1; min-width: 0; }
.ui-row__label { display: block; font-weight: var(--weight-medium); }
.ui-row__hint { display: block; font-size: var(--text-sm); color: var(--ink-3); margin-top: 2px; }
.ui-row__trail { flex: none; font-size: var(--text-sm); color: var(--ink-3); display: inline-flex; align-items: center; gap: var(--space-1); }
.ui-row--danger .ui-row__label, .ui-row--danger .ui-row__icon { color: var(--st-red); }

/* ---------------------------------------------------------------- Media tiles (clip, project, template, campaign) */
.ui-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
@media (min-width: 768px) { .ui-tiles { grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--space-4); } }
.ui-tiles--wide { grid-template-columns: repeat(1, minmax(0, 1fr)); }
@media (min-width: 560px) { .ui-tiles--wide { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); } }
.ui-tile { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.ui-tile__media {
  position: relative; aspect-ratio: 9 / 16; border-radius: var(--radius-lg); overflow: hidden;
  /* --stage, not a surface token: the badges on top are fixed white, so the ground under them
     must not flip with the theme (dark-theme trap #1). Real thumbnails cover it anyway. */
  background: var(--stage, #0b0b0d); display: block;
  transition: transform var(--dur-press) var(--ease-out);
}
.ui-tile--landscape .ui-tile__media { aspect-ratio: 16 / 9; }
.ui-tile__media:active { transform: scale(0.98); }
.ui-tile__hit { position: absolute; inset: 0; }
.ui-tile__media img, .ui-tile__media video { width: 100%; height: 100%; object-fit: cover; display: block; }
.ui-tile__tl { position: absolute; left: var(--space-2); top: var(--space-2); display: flex; gap: var(--space-1); }
.ui-tile__tr { position: absolute; right: var(--space-1); top: var(--space-1); }
.ui-tile__br { position: absolute; right: var(--space-2); bottom: var(--space-2); font-size: var(--text-xs); font-weight: var(--weight-semibold); color: #ffffff; text-shadow: 0 1px 2px rgba(0,0,0,0.6); }
.ui-tile__menu {
  width: 36px; height: 36px; border: 0; border-radius: var(--radius-full); background: rgba(0, 0, 0, 0.35);
  color: #ffffff; display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.ui-tile__title {
  font-size: var(--text-md); font-weight: var(--weight-medium); line-height: 1.3; color: var(--ink); text-decoration: none;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ui-tile__meta { font-size: var(--text-sm); color: var(--ink-3); }
.ui-tile__actions { display: flex; gap: var(--space-1); }
.ui-tile__actions .ui-btn { flex: 1; }
@media (max-width: 767px) { .ui-tile__actions { display: none; } } /* phones use the "..." sheet */

/* ---------------------------------------------------------------- Sheet / dialog */
/* One <dialog>: centred dialog on desktop, bottom sheet on a phone. Opened by ui-sheet controller. */
.ui-sheet {
  border: 0; padding: 0; background: var(--surface); color: var(--ink);
  width: min(520px, calc(100vw - 32px)); max-height: calc(100dvh - 64px); border-radius: var(--radius-xl);
  box-shadow: var(--elev-dialog); overflow: auto;
  opacity: 1; transform: none;
  transition: opacity var(--dur-enter) var(--ease-out), transform var(--dur-enter) var(--ease-out),
              overlay var(--dur-enter) allow-discrete, display var(--dur-enter) allow-discrete;
}
.ui-sheet:not([open]) { opacity: 0; transform: translateY(8px) scale(0.98); }
@starting-style { .ui-sheet[open] { opacity: 0; transform: translateY(8px) scale(0.98); } }
.ui-sheet::backdrop { background: rgba(0, 0, 0, 0.5); transition: opacity var(--dur-enter) var(--ease-out); }
.ui-sheet__inner { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-4); }
.ui-sheet__handle { display: none; }
.ui-sheet__title { margin: 0; font-size: var(--text-lg); font-weight: var(--weight-semibold); }
@media (max-width: 767px) {
  .ui-sheet {
    width: 100vw; max-width: 100vw; margin: auto 0 0; border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    max-height: 88dvh; padding-bottom: env(safe-area-inset-bottom);
  }
  .ui-sheet:not([open]) { transform: translateY(100%); }
  @starting-style { .ui-sheet[open] { transform: translateY(100%); } }
  .ui-sheet__inner { padding: var(--space-3) var(--space-4) var(--space-5); }
  .ui-sheet__handle { display: block; align-self: center; width: 40px; height: 5px; border-radius: var(--radius-full); background: var(--line-strong); }
}

/* ---------------------------------------------------------------- Form fields */
.ui-field { display: flex; flex-direction: column; gap: var(--space-1); }
.ui-field__label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--ink-soft); }
.ui-field__hint { font-size: var(--text-xs); color: var(--ink-3); }
.ui-field__error { font-size: var(--text-xs); color: var(--st-red); }
.ui-input {
  height: 44px; padding: 0 var(--space-3); border: 1px solid var(--line-strong); border-radius: var(--radius-md);
  background: var(--surface); color: var(--ink); font: inherit; font-size: var(--text-md); width: 100%; box-sizing: border-box;
  transition: border-color var(--dur-press) var(--ease-out), box-shadow var(--dur-press) var(--ease-out);
}
textarea.ui-input { height: auto; min-height: 96px; padding: var(--space-3); resize: vertical; }
.ui-input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
@media (max-width: 767px) { .ui-input { font-size: var(--text-lg); } }
/* The paste-a-link field with its button inside - the one control every clipper has now. */
.ui-linkbar { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1); padding-left: var(--space-3); border: 1px solid var(--line-strong); border-radius: var(--radius-full); background: var(--surface); }
.ui-linkbar:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.ui-linkbar input { flex: 1; min-width: 0; border: 0; outline: none; background: transparent; color: var(--ink); font: inherit; font-size: var(--text-lg); height: 40px; }

/* ---------------------------------------------------------------- Toolbar */
.ui-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-4); }
.ui-toolbar__spacer { flex: 1; }
@media (max-width: 767px) {
  .ui-toolbar__scroll { display: flex; gap: var(--space-2); overflow-x: auto; scrollbar-width: none; margin: 0 calc(var(--space-4) * -1); padding: 0 var(--space-4); }
}

/* ---------------------------------------------------------------- Loading and progress */
.ui-skeleton, .ui-skeleton.ui-tile__media { background: var(--surface-2); border-radius: var(--radius-md); position: relative; overflow: hidden; }
.ui-skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, light-dark(rgba(255,255,255,0.6), rgba(255,255,255,0.06)), transparent);
  transform: translateX(-100%); animation: ui-shimmer 1.4s infinite;
}
.ui-skeleton--line { height: 14px; border-radius: var(--radius-sm); }
@keyframes ui-shimmer { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .ui-skeleton::after { animation: none; } }
.ui-progress { height: 6px; border-radius: var(--radius-full); background: var(--surface-2); overflow: hidden; }
.ui-progress__bar { height: 100%; background: var(--primary); border-radius: inherit; transition: width var(--dur-enter) var(--ease-out); }

/* ---------------------------------------------------------------- Phone tab bar (shared/ui/_tabbar)
   Shown up to 900px, the same width at which the sidebar turns into a drawer: there is always
   exactly one way to get around, never both and never neither. Under the drawer and its scrim
   (35/40) and under bottom sheets, so anything that opens over the page also covers the bar. */
.ui-tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 34;
  display: flex; align-items: center; justify-content: space-around; padding: 0 var(--space-1);
  height: calc(64px + env(safe-area-inset-bottom)); padding-bottom: env(safe-area-inset-bottom);
  background: var(--surface); border-top: 1px solid var(--line);
}
.ui-tabbar__item {
  flex: 1 1 0; min-width: 0; height: 52px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  padding: 0; border: 0; background: none; font: inherit; cursor: pointer;
  font-size: 11px; font-weight: var(--weight-medium); color: var(--ink-2); text-decoration: none;
  transition: color var(--dur-press) var(--ease-out);
}
.ui-tabbar__item svg { width: 22px; height: 22px; }
.ui-tabbar__item[aria-current="page"] { color: var(--primary); font-weight: var(--weight-semibold); }
.ui-tabbar__new {
  flex: none; width: 52px; height: 52px; margin: 0 var(--space-1); border-radius: var(--radius-full);
  background: var(--primary); color: #ffffff; display: inline-flex; align-items: center; justify-content: center;
  transition: transform var(--dur-press) var(--ease-out);
}
.ui-tabbar__new:active { transform: scale(0.94); }
@media (min-width: 901px) { .ui-tabbar { display: none; } }
.ui-tabbar--preview { position: static; width: 100%; height: 72px; padding-bottom: 0; border-top: 0; } /* only on /design */
@media (min-width: 901px) { .ui-tabbar.ui-tabbar--preview { display: flex; } }

/* ---------------------------------------------------------------- Sidebar nav (shared/_sidebar, _nav_item, _nav_subitem) */
.ui-nav-group { display: flex; flex-direction: column; gap: 2px; }
.ui-nav-group + .ui-nav-group { margin-top: var(--space-3); }
.ui-nav-group__label { font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--ink-3); padding: 0 var(--space-3) var(--space-1); }
.ui-nav-item {
  height: 33px; padding: 0 var(--space-3); border-radius: var(--radius-full); display: flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-md); font-weight: var(--weight-medium); color: var(--ink-soft); text-decoration: none;
  transition: background var(--dur-press) var(--ease-out), color var(--dur-press) var(--ease-out);
}
.ui-nav-item svg { width: 18px; height: 18px; flex: none; color: var(--ink-3); }
.ui-nav-item:hover { background: var(--surface-2); color: var(--ink); }
/* The soft pill: only the page you are on. A group's own row (Library, Billing, Settings) just
   turns darker while one of its pages is open, so there is never more than one pill. */
.ui-nav-item[aria-current="page"] { background: light-dark(#ffffff, #2a2a30); color: var(--ink); font-weight: var(--weight-semibold); box-shadow: 0 1px 2px rgba(24, 24, 27, 0.06); }
.ui-nav-item[aria-current="page"] svg, .ui-nav-group__summary.is-active svg:first-child { color: var(--primary); }
.ui-nav-group__summary.is-active { color: var(--ink); font-weight: var(--weight-semibold); }
/* Earn: the brand red on its icon only. It used to be a filled red row that read as the page you
   were on, whatever page that was. */
.ui-nav-item--accent svg { color: var(--primary); }
.ui-nav-item--sub { height: 30px; font-size: var(--text-sm); }
.ui-nav-item__trail { margin-left: auto; font-size: var(--text-xs); color: var(--ink-3); }
.ui-nav-group__summary { cursor: pointer; list-style: none; }
.ui-nav-group__summary::-webkit-details-marker { display: none; }
.ui-nav-group__summary::marker { content: ""; }
.ui-nav-group__chevron { margin-left: auto; transition: transform var(--dur-enter) var(--ease-out); }
.ui-nav-details[open] > .ui-nav-group__summary .ui-nav-group__chevron { transform: rotate(90deg); }
.ui-nav-group__items { display: flex; flex-direction: column; gap: 2px; margin: 2px 0 4px 22px; }

/* ---------------------------------------------------------------- App shell (step 2)
   The sidebar sits on the frame and the page on its own rounded surface (desktop); on a phone
   the tab bar sits at the bottom (the burger stays top left for the rest), and everything that
   lives at the bottom of the screen stands clear of it. */
.sidebar { background: var(--frame); }
@media (min-width: 901px) {
  .shell { background: var(--frame); }
  .shell .sidebar { border-right: 0; }
  .shell .main {
    margin: 8px 8px 8px 0; min-height: calc(100dvh - 16px);
    background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-lg);
  }
  .shell.nav-collapsed .main { margin-left: 8px; }
  .shell .topbar { border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
}
@media (max-width: 900px) {
  .sidebar .ui-nav-item { height: 42px; }
  .shell--tabbar .content { padding-bottom: calc(160px + env(safe-area-inset-bottom)); }
  /* The chat bubble is an iframe with its position inline (shared/_tawk_chat), hence !important. */
  body:has(.shell--tabbar) [data-tawk-frame] { bottom: calc(64px + env(safe-area-inset-bottom)) !important; }
  body:has(.shell--tabbar) .toast-stack,
  body:has(.shell--tabbar) .ask-toast { bottom: calc(160px + env(safe-area-inset-bottom)); }
  body:has(.shell--tabbar) .cookie-consent { bottom: calc(76px + env(safe-area-inset-bottom)); }
}
@media (max-width: 640px) {
  .shell--tabbar .select-bar__actions { bottom: calc(78px + env(safe-area-inset-bottom)); }
}

/* ---------------------------------------------------------------- Clip card (clips/_clip, step 3)
   Two columns of posters on a phone, more on a wide screen. The player, the score and the
   selection layer keep their own rules in application.css; this is the layout around them. */
.clip-grid { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); }
@media (max-width: 640px) { .clip-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; } }

.clip-card { border-radius: var(--radius-lg); }
/* The score steps aside while the clip plays: iOS puts its own fullscreen and mute buttons in the
   top corners of a playing video (clip_video_controller hides the play overlay on play). */
.clip-card:has(.clip-card__play[hidden]) .clip-card__topbar { opacity: 0; pointer-events: none; }
.clip-card__topbar { transition: opacity var(--dur-press) var(--ease-out); }
.clip-card__topbar-actions { display: flex; gap: 6px; margin-left: auto; }
.clip-card__edit:hover { background: var(--primary); }

/* Like and dislike on the poster's right edge. Translucent dark rounds so they read on any
   footage; red when it is your pick. Hover only where there is a real pointer - a tap would
   otherwise leave the "hover" red stuck on a phone. */
.clip-card__rail {
  position: absolute; top: 50%; right: 8px; transform: translateY(-50%); z-index: 3;
  display: flex; flex-direction: column; gap: 16px;
}
.clip-card__railbtn {
  position: relative; width: 34px; height: 34px; padding: 0; display: grid; place-items: center;
  border: 0; border-radius: var(--radius-full); cursor: pointer; background: rgba(0, 0, 0, 0.45); color: #ffffff;
  transition: background var(--dur-press) var(--ease-out), color var(--dur-press) var(--ease-out);
}
@media (hover: hover) { .clip-card__railbtn:hover { background: rgba(0, 0, 0, 0.6); color: var(--primary); } }
.clip-card__railbtn.is-active { color: var(--primary); }
.clip-card__railbtn.is-active svg { fill: currentColor; }
.clip-card__railcount {
  position: absolute; bottom: -14px; left: 50%; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 10px; font-weight: var(--weight-semibold); color: #ffffff; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
@media (max-width: 640px) {
  .clip-card__rail { right: 6px; gap: 12px; }
  .clip-card__railbtn { width: 36px; height: 36px; }
  .clip-card__remove { width: 32px; height: 32px; }
}

.clip-card__body { display: flex; flex-direction: column; gap: 6px; padding: var(--space-3); }
.clip-card__title {
  font-size: var(--text-md); font-weight: var(--weight-semibold); line-height: var(--leading-tight); color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.clip-card__twin { margin-top: 0; width: fit-content; }
.clip-card__meta { margin: 0; }
/* The buttons sit at the bottom of the card, so across a row of cards they line up whatever the
   title's length. Icons of one size sharing the width (owner, 2026-10-29: a red "Post" pill on
   every clip was too much); Post is told apart by its red upload arrow and its tooltip. */
.clip-card { display: flex; flex-direction: column; }
.clip-card__body { flex: 1 1 auto; }
.clip-card__row { display: flex; align-items: center; gap: 6px; margin-top: auto; padding-top: 4px; }
.clip-card__row .ui-btn { height: 34px; min-height: 34px; border-radius: var(--radius-sm); }
.clip-card__row .ui-btn--icon { flex: 1 1 0; width: auto; min-width: 0; padding: 0; }
.clip-card__post { position: relative; }
.clip-card__post svg { color: var(--primary); flex: none; }
@media (max-width: 640px) {
  .clip-card__body { padding: 10px; }
  .clip-card__title { font-size: var(--text-sm); }
  .clip-card__from, .clip-card__wide { display: none; }
  .clip-card__row .ui-btn { height: 40px; min-height: 40px; }
}

/* The "..." sheet */
.clip-card__sheethead { display: flex; align-items: flex-start; gap: var(--space-2); }
.clip-card__sheethead .ui-sheet__title { flex: 1; min-width: 0; line-height: var(--leading-tight); }
.clip-card__caption { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-3) var(--space-4); background: var(--surface-2); border-radius: var(--radius-lg); }
.clip-card__caption-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.clip-card__desc { margin: 0; font-size: var(--text-md); line-height: var(--leading-normal); color: var(--ink-2); }
.clip-card__tags { display: flex; flex-wrap: wrap; gap: 5px; }
.clip-card__hashtag { font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--primary); background: var(--primary-tint); padding: 2px 8px; border-radius: var(--radius-full); }
.clip-card__copied { display: none; }
.clip-card__copy.is-copied { color: var(--st-green); }
.clip-card__copy.is-copied .clip-card__copied { display: inline; }
.clip-card__copy.is-copied > span:not(.clip-card__copied) { display: none; }
.clip-card__sharehint { cursor: default; }
.clip-card__sharehint:hover { background: transparent; }
.ui-row.is-copied .ui-row__label, .ui-row.is-copied .ui-row__icon { color: var(--st-green); }

/* Billing on a phone: the recommended plan first (app/views/billing/show). Same width at which
   .pricing-grid stacks into one column. */
@media (max-width: 900px) { .pricing-grid--billing > .is-highlighted { order: -1; } }

/* A one-line note on a page (the watermark on a project's clips): quiet surface, the link is the
   only red. */
.ui-note {
  display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-4); padding: var(--space-2) var(--space-3);
  background: var(--surface-2); border-radius: var(--radius-md); font-size: var(--text-sm); color: var(--ink-2);
}
.ui-note__icon { display: inline-flex; flex: none; color: var(--primary); }
.ui-note__text { flex: 1; min-width: 0; }
.ui-note__action { flex: none; font-weight: var(--weight-semibold); color: var(--primary); text-decoration: none; white-space: nowrap; }
.ui-note__action:hover { text-decoration: underline; }
.clip-card__crown { color: var(--primary); }

/* Clips still rendering (shared/_clips_empty): on the clip cards' own grid, so a placeholder is
   exactly the size of the clip that replaces it (owner, 2026-10-29). On a wide screen only the
   first row shows - extra rows collapse to nothing - so the row is always full whatever the
   column count; on a phone, two rows of two. */
.clip-pending__card { border-radius: var(--radius-lg); }
@media (min-width: 641px) {
  .clip-pending.clip-grid { grid-template-rows: auto; grid-auto-rows: 0; row-gap: 0; overflow: hidden; }
}
@media (max-width: 640px) {
  .clip-pending__card:nth-child(n + 5) { display: none; }
}

/* The one-tap caption copy in the card's button row (clips/_clip). */
.clip-card__copytext-idle, .clip-card__copytext-done { display: inline-flex; }
.clip-card__copytext-done { display: none; }
.clip-card__copytext.is-copied { color: var(--st-green); }
.clip-card__copytext.is-copied .clip-card__copytext-idle { display: none; }
.clip-card__copytext.is-copied .clip-card__copytext-done { display: inline-flex; }

/* What a posted clip did (views, likes, comments): grey line icons, same quiet tone as the length
   beside them - the numbers are for a glance, not for the eye to land on (owner, 2026-10-29). */
.clip-card__stat svg { color: var(--ink-3); }

/* A project's settings chips (videos/_status_panel): as they were on a wide screen, folded into one
   line that opens a sheet on a phone. --always folds at every width (templates list). */
.settings-fold__line {
  display: none; align-items: center; gap: var(--space-2); width: 100%; margin-top: var(--space-4);
  min-height: var(--tap); padding: 0 var(--space-3); border: 0; border-radius: var(--radius-md);
  background: var(--surface-2); color: var(--ink-2); font: inherit; font-size: var(--text-sm); text-align: left; cursor: pointer;
}
.settings-fold__label { flex: none; font-weight: var(--weight-semibold); color: var(--ink); }
.settings-fold__values { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The chevron is drawn here rather than as an icon: every byte of the project panel's markup travels
   over the size-capped websocket on each status change (see the partial). */
.settings-fold__line::after {
  content: ""; flex: none; width: 7px; height: 7px; margin-right: 4px;
  border-right: 2px solid var(--ink-3); border-top: 2px solid var(--ink-3); transform: rotate(45deg);
}
.settings-fold__line:hover { color: var(--ink); }
.settings-fold .ui-sheet .settings-chips { margin: 0; }
.settings-fold--always .settings-fold__line { display: flex; margin-top: var(--space-2); }
@media (max-width: 640px) {
  .settings-fold__wide { display: none; }
  .settings-fold__line { display: flex; }
}

/* Dashboard: credits, plan and projects in one card, three columns at every width. */
.dash-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; padding: 0; margin-bottom: var(--space-6); }
.dash-summary__cell { padding: var(--space-4) var(--space-5); min-width: 0; }
.dash-summary__cell + .dash-summary__cell { border-left: 1px solid var(--line); }
.dash-summary__value { font-family: var(--font-mono); font-size: 26px; font-weight: var(--weight-semibold); letter-spacing: -0.02em; margin-top: var(--space-1); }
@media (max-width: 640px) {
  .dash-summary { margin-bottom: var(--space-5); }
  .dash-summary__cell { padding: var(--space-3); }
  .dash-summary__value { font-size: var(--text-xl); }
  .dash-summary .stat__label { font-size: 9.5px; }
  .dash-summary .stat__action { font-size: 11px; }
}

/* Content plan: the set-once panels under the calendar, folded into one line each
   (posting_plans/show). */
.plan-fold { margin-top: var(--space-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.plan-fold + .plan-fold { margin-top: var(--space-2); }
.plan-fold__head {
  display: flex; align-items: center; gap: var(--space-3); min-height: 52px; padding: 0 var(--space-4);
  cursor: pointer; list-style: none; border-radius: var(--radius-lg);
}
.plan-fold__head::-webkit-details-marker { display: none; }
.plan-fold__head::marker { content: ""; }
.plan-fold__title { font-weight: var(--weight-semibold); color: var(--ink); }
.plan-fold__meta { flex: 1; min-width: 0; font-size: var(--text-sm); color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.plan-fold__chevron { flex: none; color: var(--ink-3); transition: transform var(--dur-enter) var(--ease-out); }
.plan-fold[open] > .plan-fold__head .plan-fold__chevron { transform: rotate(90deg); }
/* The panels inside lose their own card: the fold is the card now. */
.plan-fold > .panel, .plan-fold > #plan_settings { margin: 0 !important; border: 0; box-shadow: none; background: transparent; padding-top: 0; }

/* The phone's week list: rows a thumb can use. 44px tall, and the x is a real 36px button in the
   middle of the right edge instead of a 15px glyph in the corner (owner audit, 2026-10-29). */
@media (max-width: 760px) {
  .calendar-agenda .cal-post { min-height: 44px; padding: 6px 44px 6px 10px; border-radius: var(--radius-sm); font-size: var(--text-sm); }
  .calendar-agenda .cal-post__remove {
    top: 50%; right: 4px; transform: translateY(-50%); width: 36px; height: 36px; padding: 0;
    display: grid; place-items: center; border-radius: var(--radius-full); opacity: .85;
  }
  .calendar-agenda .cal-post__remove svg { width: 15px; height: 15px; }
  .calendar-agenda .cal-free--row { min-height: 44px; }
}

/* Every .modal dialog as a bottom sheet on a phone - the publish composer, the confirm box, the
   dislike reason, the content plan's clip picker - like the clip's "..." sheet and the Actions
   menu: full width, rounded top, a handle, slides up; swipe down or tap outside to close
   (swipe_close_controller). A swipe is a cancel: the confirm box presets returnValue "cancel". */
@media (max-width: 640px) {
  .modal {
    width: 100vw; max-width: 100vw; margin: auto 0 0; border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    padding-bottom: env(safe-area-inset-bottom);
    transition: transform var(--dur-enter) var(--ease-out), overlay var(--dur-enter) allow-discrete, display var(--dur-enter) allow-discrete;
  }
  .modal:not([open]) { transform: translateY(100%); }
  @starting-style { .modal[open] { transform: translateY(100%); } }
  .modal::before {
    content: ""; display: block; width: 40px; height: 5px; margin: 8px auto 0;
    border-radius: var(--radius-full); background: var(--line-strong);
  }
  .modal .modal__card { padding: 12px 16px 20px; }
  .modal--wide .modal__card { max-height: calc(92dvh - 13px); overflow-y: auto; }
  .modal--picker .modal__card { max-height: calc(92dvh - 13px); } /* it scrolls inside its own frame */
  .modal__close { top: 14px; right: 12px; width: 36px; height: 36px; }
  .modal__actions .btn { flex: 1; min-height: var(--tap); }
}
@media (prefers-reduced-motion: reduce) { .modal { transition: none; } }

/* Page loading (application.js "Page loading"): Turbo's progress bar in the brand red, and the
   skeleton that stands in for a page that is slow to arrive. */
.turbo-progress-bar { height: 3px; background: var(--primary); }
.content.is-navigating > :not(.nav-skeleton) { display: none; }
.nav-skeleton { display: flex; flex-direction: column; gap: var(--space-3); animation: nav-skeleton-in var(--dur-enter) var(--ease-out); }
@keyframes nav-skeleton-in { from { opacity: 0; } to { opacity: 1; } }
.nav-skeleton__title { width: 40%; max-width: 260px; height: 28px; border-radius: var(--radius-sm); }
.nav-skeleton__sub { width: 60%; max-width: 420px; margin-bottom: var(--space-4); }
.nav-skeleton__tile { display: flex; flex-direction: column; gap: var(--space-2); }
.nav-skeleton__poster { aspect-ratio: 9 / 16; border-radius: var(--radius-lg); }
.nav-skeleton__thumb { aspect-ratio: 16 / 9; border-radius: var(--radius-lg); }
.nav-skeleton__short { width: 50%; }
.nav-skeleton__cards { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.nav-skeleton__rows { display: flex; flex-direction: column; gap: var(--space-3); }
.nav-skeleton__row { height: 64px; border-radius: var(--radius-lg); }
@media (max-width: 640px) { .nav-skeleton__cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; } }

/* Library (videos/index) on a phone: one "new" button fewer, thumb-sized card buttons, and the
   card's picture shimmering while it loads instead of a blank box. */
.lib-topbar-action { display: contents; }
@media (max-width: 900px) { .shell--tabbar .lib-topbar-action { display: none; } }
@media (max-width: 640px) {
  .lib-table--cards .lib-star, .lib-table--cards .lib-actions { width: 40px; height: 40px; }
}
.lib-table--cards .lib-thumb:has(img) {
  background: linear-gradient(100deg, var(--surface-2) 30%, var(--line) 50%, var(--surface-2) 70%) 0 0 / 300% 100%;
  animation: lib-thumb-shimmer 1.4s linear infinite;
}
@keyframes lib-thumb-shimmer { to { background-position: -150% 0; } }
@media (prefers-reduced-motion: reduce) { .lib-table--cards .lib-thumb:has(img) { animation: none; } }

/* Motion (redesign step 6): a pressed control answers the finger. Buttons give a little; rows,
   menu items and tabs darken instead of shrinking - a shrinking row moved its edge out from under
   a finger that pressed near it, the release landed outside and the tap was lost (owner,
   2026-10-29: the sidebar "не завжди переходить"). */
.ui-btn:active:not(:disabled) { transform: scale(0.97); }
.ui-tabbar__item:active, .ui-nav-item:active, .ui-row:active { opacity: 0.7; }
.ui-btn, .ui-tabbar__item, .ui-nav-item, .ui-row { transition-property: background, color, transform, opacity; }
@media (prefers-reduced-motion: reduce) { .ui-btn:active { transform: none; } }

/* A folded settings group's line of what is set (fold_summary_controller): one line, cut short
   with an ellipsis rather than wrapping under the title. */
.form-block__summary { min-height: var(--tap); }
.form-block__summary .form-block__summary-hint { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--text-xs); }
.form-block--fold[open] .form-block__summary .form-block__summary-hint { visibility: hidden; }

/* ---------------------------------------------------------------- The older classes, in the new shape
   Every app page not rebuilt by hand still uses .btn, .panel, .card and .input. Rather than rewrite
   each page, those classes take the new scales here, inside the signed-in app only (.shell): the
   landing and SEO pages keep their own look. One place, so the whole app moves together (owner,
   2026-10-29: "органічним ... перевикористовувати компоненти"). */
.shell .btn { border-radius: var(--radius-full); }
.shell .btn--icon { border-radius: var(--radius-full); }
.shell .card, .shell .panel { border-radius: var(--radius-lg); box-shadow: none; }
.shell .input, .shell select.input, .shell .textarea { border-radius: var(--radius-md); }
@media (max-width: 640px) {
  .shell .confirm-banner__action { min-height: 40px; }
}

/* Top bar, right: the credit balance and the account menu (shared/_balance_card, _user_menu). */
.topbar-credits {
  display: inline-flex; align-items: center; gap: 4px; height: 32px; padding: 0 10px; flex: none;
  border-radius: var(--radius-full); background: var(--surface-2); color: var(--ink);
  font-family: var(--font-mono); font-size: var(--text-sm); font-weight: var(--weight-semibold); text-decoration: none;
}
.topbar-credits svg { color: var(--primary); }
.topbar-credits:hover { background: var(--line); }
.topbar-credits.is-empty { color: var(--primary); background: var(--primary-tint); }
.topbar-wallet { display: inline-flex; align-items: center; flex: none; border-radius: var(--radius-full); background: var(--surface-2); }
.topbar-wallet .topbar-upgrade {
  height: 32px; margin: 0; padding: 0 12px 0 10px; border: 0; border-left: 1px solid var(--line);
  border-radius: 0 var(--radius-full) var(--radius-full) 0; background: none; color: var(--primary); font-weight: var(--weight-semibold);
}
.topbar-wallet .topbar-upgrade:hover { background: var(--line); }
.topbar-wallet:has(.topbar-credits.is-empty) { background: var(--primary-tint); }
.topbar-wallet .topbar-credits.is-empty { background: none; }
.topbar-wallet .topbar-credits:has(+ .topbar-upgrade) { border-radius: var(--radius-full) 0 0 var(--radius-full); }
.user-menu { flex: none; }
.user-menu__button { display: grid; place-items: center; width: 36px; height: 36px; padding: 0; border: 0; border-radius: var(--radius-full); background: none; cursor: pointer; }
.user-menu__button .avatar { width: 32px; height: 32px; border-radius: var(--radius-full); }
.user-menu__panel { top: 44px; min-width: 240px; padding: 6px; border-radius: var(--radius-md); }
.user-menu__who { display: flex; flex-direction: column; gap: 2px; padding: 8px 10px 10px; min-width: 0; }
.user-menu__name { font-weight: var(--weight-semibold); font-size: var(--text-md); }
.user-menu__email { font-size: var(--text-xs); color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-menu__label { padding: 6px 10px 2px; font-size: var(--text-xs); color: var(--ink-3); }
.user-menu__rule { border: 0; border-top: 1px solid var(--line); margin: 4px 0; }
.user-menu .menu__item { min-height: 38px; border-radius: var(--radius-sm); }
.shell .topbar { gap: 10px; }
