/* Yuli hub design tokens + global mobile helpers — shared across all hub pages.
   Served from /hub/_pub/_tokens.css (public path, no auth so login.html reaches it).
   Kyoto Slate restyle 2026-07-25 — visual authority: docs/mocks/hub-kyoto-2026-07-25.html.
   Legacy variable names (--bg, --accent, --font, …) keep their meaning so page CSS
   written against the old tokens picks up Kyoto values without a rename sweep.
   Page-specific tokens stay inline in each page. */

@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/ibm-plex-sans-var.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/ibm-plex-sans-400-italic.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/ibm-plex-mono-500.woff2') format('woff2');
}

:root {
  color-scheme: dark;

  /* Kyoto Slate surfaces + text */
  --bg: hsl(220, 12%, 10%);
  --s1: hsl(220, 10%, 16%);
  --s2: hsl(220, 9%, 20%);
  --s3: hsl(220, 9%, 24%);
  --t1: hsl(220, 12%, 95%);
  --t2: hsl(220, 8%, 65%);
  --t3: hsl(220, 6%, 52%);
  --sep: hsla(220, 10%, 95%, 0.1);
  --glass: hsla(220, 10%, 12%, 0.6);

  /* Accent (320) */
  --acc: hsl(320, 85%, 70%);
  --acc-hi: hsl(320, 85%, 78%);
  --acc-ghost: hsla(320, 85%, 70%, 0.12);

  /* Semantic family — lead estados + visit types map here:
     sin contacto=neu · sin respuesta=warn · contactado/con notas=info ·
     en seguimiento/agendado=prog · asesorado/cerrado=good · rechazado=bad ·
     visitas: coordinada=info · fría=warn · asesoramiento=prog · virtual=neu */
  --good: hsl(160, 85%, 60%);
  --bad: hsl(350, 90%, 68%);
  --warn: hsl(50, 95%, 65%);
  --prog: hsl(25, 90%, 68%);
  --info: hsl(215, 90%, 72%);
  --neu: hsl(320, 10%, 65%);

  /* Type */
  --ui: 'IBM Plex Sans', 'Segoe UI', system-ui, sans-serif;
  --data: 'IBM Plex Mono', Consolas, monospace;
  --tk-tight: -0.015em;
  --tk-norm: 0em;
  --tk-wide: 0.005em;
  --tk-caps: 0.08em;

  /* Atmosphere */
  --shadow-card: 0 0 1px hsla(0, 0%, 100%, 0.12), 0 16px 44px -12px hsla(220, 40%, 4%, 0.7), inset 0 1px 0 hsla(0, 0%, 100%, 0.04);
  --wash: linear-gradient(to bottom, hsla(220, 30%, 90%, 0.03), transparent 70%);
  --mo: 150ms cubic-bezier(0.21, 1, 0.81, 1);

  /* Legacy aliases — old token names, Kyoto values */
  --font: var(--ui);
  --accent: var(--acc);
  --accent-hover: var(--acc-hi);
  --accent-dim: hsla(320, 85%, 70%, 0.3);
  --bg-alt: var(--s1);
  --bg-card: var(--s1);
  --text: var(--t1);
  --text-sub: var(--t2);
  --text-dim: var(--t3);
  --border: var(--sep);
  --r-lg: 22px;
  --r-md: 18px;
  --r-sm: 13px;
  --tap-min: 44px;
}

html { font-size: 17px; }

/* ---------- Shared body atmosphere (Kyoto washes + grain) ---------- */
body {
  background-color: var(--bg);
  background-image:
    radial-gradient(1100px 500px at 8% -10%, hsla(320, 85%, 70%, 0.10), transparent 60%),
    radial-gradient(900px 480px at 100% 0%, hsla(215, 90%, 72%, 0.08), transparent 55%),
    radial-gradient(800px 600px at 50% 115%, hsla(160, 85%, 60%, 0.06), transparent 60%);
  background-attachment: fixed;
  font-feature-settings: 'tnum';
}
body::after {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  opacity: 0.025;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- Left rail (replaces the horizontal .nav on every page) ----------
   Markup contract (copy from docs/mocks/hub-kyoto-2026-07-25.html):
   .approw > aside.rail (.rmark svg, a.rlink×N with .rtip tooltips, .rme avatar
   + .rout logout) + .rcontent (the page's old <main>). Badge elements keep
   their historic IDs (#msg-badge, #agenda-badge) restyled as .rdot — page JS
   keeps setting textContent; font-size:0 hides the number, :empty hides the dot. */
.approw { display: flex; align-items: stretch; min-height: 100vh; min-height: 100dvh; }
.rail {
  flex: 0 0 60px;
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1px, 0.35vh, 3px);
  padding: max(clamp(6px, 1.5vh, 14px), env(safe-area-inset-top)) 0
           max(clamp(6px, 1.5vh, 12px), env(safe-area-inset-bottom));
  background: var(--glass);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-right: 1px solid var(--sep);
  z-index: 40;
}
/* The rail does NOT scroll by default, on purpose: .rtip tooltips are absolutely
   positioned OUTSIDE the rail (left: 100% + 10px), and CSS has no way to keep
   them — `overflow-x: visible` computes to `auto` the moment overflow-y isn't
   visible, so ANY scrolling rail clips its own tooltips on both axes.
   The two needs live on different devices, so they're scoped apart below. */
.rail::-webkit-scrollbar { display: none; }
/* Touch: dvh shrinks when the browser toolbar appears and a height media query
   can't see it (it measures the LARGE viewport), so scrolling is always on.
   Costs nothing — tooltips are hover-only and never fire here. */
@media (hover: none) {
  .rail { overflow-y: auto; overflow-x: hidden; scrollbar-width: none; }
}
/* Mouse + genuinely short window. Here the height query IS reliable (no dynamic
   toolbar), so tooltips are traded for reachability only in this narrow case. */
@media (hover: hover) and (max-height: 560px) {
  .rail { overflow-y: auto; overflow-x: hidden; scrollbar-width: none; }
}
.rcontent { flex: 1; min-width: 0; }
.rmark {
  width: clamp(26px, 4.2vh, 36px);
  height: clamp(26px, 4.2vh, 36px);
  margin-bottom: clamp(5px, 1.8vh, 16px);
  flex: 0 0 auto;
}
.rlink {
  position: relative;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  border-radius: 12px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--t3);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all var(--mo);
  text-decoration: none;
}
.rlink svg { width: 19px; height: 19px; stroke: currentColor; fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.rlink:hover { color: var(--acc-hi); background: hsla(320, 85%, 78%, 0.08); }
.rlink.active {
  color: var(--acc);
  background: linear-gradient(var(--s1), var(--s1)) padding-box, linear-gradient(120deg, hsl(320, 85%, 62%), hsl(320, 85%, 78%)) border-box;
}
.rdot {
  position: absolute;
  top: 7px;
  right: 7px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--warn);
  font-size: 0;
  color: transparent;
  overflow: hidden;
}
.rdot:empty { display: none; }
.rtip {
  display: none;
  position: absolute;
  left: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%);
  z-index: 20;
  background: hsla(220, 10%, 18%, 0.94);
  backdrop-filter: blur(16px);
  color: var(--t1);
  font-family: var(--ui);
  font-size: 0.76rem;
  font-weight: 500;
  white-space: nowrap;
  border-radius: 9px;
  padding: 6px 10px;
  box-shadow: var(--shadow-card);
}
/* (hover: hover) alone — deliberately NOT `and (pointer: fine)`: a touchscreen
   laptop with a mouse reports its PRIMARY pointer as coarse, which would kill
   the tooltip on a machine that hovers perfectly well. */
@media (hover: hover) {
  .rlink:hover .rtip { display: block; }
}
.rlink:focus-visible .rtip { display: block; }
.rsep { width: 26px; height: 1px; background: var(--sep); margin: clamp(2px, 0.9vh, 8px) 0; flex: 0 0 auto; }
/* .rme is sticky-pinned to the bottom of the scrolling rail: the tap targets
   above are locked at 44px (--tap-min, accessibility), so on a short viewport
   the icon column has to scroll — but avatar + logout must stay reachable
   without scrolling. Sticky keeps them parked while the icons pass behind. */
.rme {
  margin-top: auto;
  position: sticky;
  bottom: calc(-1 * clamp(6px, 1.5vh, 12px));
  z-index: 2;
  padding: clamp(4px, 1vh, 8px) 0 clamp(6px, 1.5vh, 12px);
  background: linear-gradient(to bottom, hsla(220, 10%, 12%, 0) 0, hsl(220, 10%, 12%) 55%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(3px, 0.8vh, 6px);
  flex: 0 0 auto;
}
.rme .rav {
  width: 32px;
  height: 32px;
  border-radius: 999px;
  background: var(--s3);
  color: var(--t1);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 0.78rem;
}
.rout {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  border: 0;
  background: transparent;
  color: var(--t3);
  font-size: 0.9rem;
  cursor: pointer;
  transition: all var(--mo);
}
.rout:hover { color: var(--bad); background: hsla(350, 90%, 68%, 0.08); }

/* ---------- Shared Kyoto recipes ---------- */
.card {
  background: var(--s1);
  background-image: var(--wash);
  border-radius: 18px;
  box-shadow: var(--shadow-card);
  padding: 18px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--s2);
  color: var(--t2);
  font-size: 0.72rem;
  font-weight: 500;
  border-radius: 999px;
  padding: 4px 10px;
  white-space: nowrap;
}
.chip .dot { width: 6px; height: 6px; border-radius: 999px; flex: 0 0 auto; }
.d-good { background: var(--good); }
.d-bad { background: var(--bad); }
.d-warn { background: var(--warn); }
.d-prog { background: var(--prog); }
.d-info { background: var(--info); }
.d-neu { background: var(--neu); }

/* ---------- Tap-target minimums (Phase 1.1) ----------
   Apple HIG / Google Material require ≥44×44 hit areas. Selectors for classes
   that don't exist on a page are no-ops.
   NOTE: index.html's 5px visit bars were replaced by .vdots in the restyle, so
   .chip is now safe to size — but chips are informational (not tapped) so they
   stay out of the tap-min list anyway. */
.btn,
.btn-action,
.btn-sm,
.tab,
.quick-action,
.cal-btn,
.toggle-btn,
.extra-btn,
.wa-link,
.yuli-modal-btn,
.rlink {
  min-height: var(--tap-min);
  min-width: var(--tap-min);
}

/* ---------- Touch feedback (Phase 1.3) ----------
   :hover either doesn't fire on touch or sticks until next tap. :active gives
   universal press feedback. Using transform avoids fighting existing background
   color rules per button class. */
.btn:active,
.btn-action:active,
.btn-sm:active,
.tab:active,
.quick-action:active,
.cal-btn:active,
.toggle-btn:active,
.extra-btn:active,
.wa-link:active,
.yuli-modal-btn:active,
.rlink:active {
  transform: scale(0.97);
  transition: transform 0.08s ease;
}

/* ---------- Modal sizing on mobile (Phase 1.4) ----------
   .yuli-modal-* lives in 3 pages (index, leads, recordatorios). Cap modal
   width to viewport, reduce padding for small screens. */
@media (max-width: 480px) {
  .yuli-modal,
  .yuli-modal.wide {
    max-width: min(100%, 380px);
    padding: 1rem;
  }
}
