/* ==========================================================================
   OBSCURA · TOKENS
   Contrato semántico. Ningún componente usa un color crudo ni un --obs-*.
   Cambiar el tema de una sección = <section data-theme="dark">.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1 · PALETA DE MARCA (valores crudos — solo se leen desde este archivo)
   -------------------------------------------------------------------------- */
:root {
  --brand-negro:   #1D1C18;
  --brand-crema:   #EAE3D6;
  --brand-arena:   #E2D8C4;
  --brand-greige:  #55503F;
  --brand-celeste: #2E6485;
  --brand-cobre:   #8A4820;

  /* Variantes aclaradas para uso sobre negro (los originales no llegan a AA) */
  --brand-celeste-lt: #6BA3C9;
  --brand-cobre-lt:   #D08A4E;

  /* Verde de estado "va bien" (tildes, barra de cerradas, punto de "Activo").
     Vive SÓLO dentro de los mockups: no es color de marca y no debe salir de
     ahí. Estaba clavado como literal #3FB56B en siete lugares de mockups.css y
     sin variante por tema — el mismo verde sobre crema y sobre negro. */
  --brand-verde:    #2F8F52;   /* sobre crema */
  --brand-verde-lt: #3FB56B;   /* sobre negro (el literal de siempre) */
}

/* --------------------------------------------------------------------------
   2 · TEMA CLARO (por defecto)
   -------------------------------------------------------------------------- */
:root,
[data-theme="light"] {
  color-scheme: light;

  --bg:          var(--brand-crema);
  --bg-elev:     var(--brand-arena);
  --bg-sunk:     #E5DDCD;

  --ink:         var(--brand-negro);
  --ink-mute:    var(--brand-greige);
  --ink-soft:    rgba(29, 28, 24, .66);   /* .62 daba 4.36:1 — no llegaba a AA */
  --ink-faint:   rgba(29, 28, 24, .38);

  --line:        rgba(29, 28, 24, .12);
  --line-strong: rgba(29, 28, 24, .24);

  /* Vidrio. --glass-rgb es el TRIPLETE, no un color: lo componen los gradientes. */
  --glass-rgb:      29, 28, 24;
  /* El especular del glimpse NO puede usar --glass-rgb, y el motivo es
     físico: acá el triplete es la TINTA OSCURA (el canto en claro es un
     contorno, no una línea de luz) y un brillo hecho con eso OSCURECE.
     Un especular es siempre más claro que la superficie. Sobre la crema el
     único lugar más claro es el blanco: donde pega la luz, el contorno
     oscuro se abre. Elegido sobre render contra tinta .42 y blanco .60. */
  --spec-rgb:       255, 255, 255;
  --glass-bg:       rgba(29, 28, 24, .025);
  --glass-bg-hover: rgba(29, 28, 24, .05);
  --glass-inner:    rgba(29, 28, 24, .10);
  --glass-blur:     10px;

  --accent:      var(--brand-celeste);
  --accent-2:    var(--brand-cobre);
  --accent-ink:  var(--brand-crema);      /* texto sobre relleno de acento */
  --accent-glow: rgba(46, 100, 133, .16);
  --ok:          var(--brand-verde);

  --shadow-card: 0 1px 2px rgba(29,28,24,.04), 0 8px 24px -12px rgba(29,28,24,.16);
  --shadow-lift: 0 2px 4px rgba(29,28,24,.05), 0 20px 48px -20px rgba(29,28,24,.26);

  --grain-opacity: .038;
  --grain-blend:   multiply;
}

/* --------------------------------------------------------------------------
   3 · TEMA OSCURO
   -------------------------------------------------------------------------- */
[data-theme="dark"] {
  color-scheme: dark;

  --bg:          var(--brand-negro);
  --bg-elev:     #24231E;
  --bg-sunk:     #161511;

  --ink:         var(--brand-crema);
  --ink-mute:    rgba(234, 227, 214, .72);
  --ink-soft:    rgba(234, 227, 214, .55);
  --ink-faint:   rgba(234, 227, 214, .32);

  --line:        rgba(234, 227, 214, .12);
  --line-strong: rgba(234, 227, 214, .28);

  --glass-rgb:      234, 227, 214;
  /* Sobre negro la luz de la casa es la CREMA y no el blanco — la misma
     lección que el canto iluminado de la 04 y el degradé del pie (8ª pasada).
     Comparado sobre render contra blanco 1.0: la diferencia es mínima y la
     crema se queda adentro del sistema de marca. */
  --spec-rgb:       234, 227, 214;
  --glass-bg:       rgba(234, 227, 214, .03);
  --glass-bg-hover: rgba(234, 227, 214, .06);
  --glass-inner:    rgba(234, 227, 214, .10);
  --glass-blur:     10px;

  --accent:      var(--brand-celeste-lt);
  --accent-2:    var(--brand-cobre-lt);
  --accent-ink:  var(--brand-negro);
  --accent-glow: rgba(107, 163, 201, .20);
  --ok:          var(--brand-verde-lt);

  --shadow-card: 0 1px 2px rgba(0,0,0,.30), 0 8px 24px -12px rgba(0,0,0,.55);
  --shadow-lift: 0 2px 4px rgba(0,0,0,.35), 0 20px 48px -20px rgba(0,0,0,.65);

  --grain-opacity: .05;
  --grain-blend:   overlay;
}

/* --------------------------------------------------------------------------
   4 · TIPOGRAFÍA
   Tres familias, tres trabajos. Las leyes están en base.css.
   -------------------------------------------------------------------------- */
:root {
  /* 'Obscura Fallback' es Georgia con las métricas de Instrument Serif
     encima (@font-face en base.css). Va INMEDIATAMENTE después de la fuente
     web: es lo que se ve durante el swap, y con las métricas igualadas el
     texto no se mueve al llegar la real. Va antes que 'Iowan Old Style' a
     propósito — Iowan es más linda pero tiene otras métricas y en macOS
     devolvía el salto. */
  --font-display: 'Instrument Serif', 'Obscura Fallback', 'Iowan Old Style', Georgia, serif;
  --font-ui:      'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
  --font-body:    'IBM Plex Sans', system-ui, -apple-system, sans-serif;

  /* Escala fluida: 390px → 1440px */
  --fs-display: clamp(2.5rem,  1.10rem + 5.75vw, 5.5rem);   /* 40 → 88 */
  --fs-numeral: clamp(2.75rem, 1.65rem + 4.50vw, 5rem);     /* 44 → 80 */
  --fs-h2:      clamp(1.75rem, 1.11rem + 2.62vw, 3rem);     /* 28 → 48 */
  --fs-h3:      clamp(1.25rem, 1.10rem + 0.62vw, 1.5rem);   /* 20 → 24 */
  /* --fs-h4 y --fs-lead eran DOS NOMBRES PARA EL MISMO TAMAÑO: mismo mínimo
     (1.0625rem) y mismo máximo (1.1875rem), y sólo cambiaba la pendiente —
     0.26vw contra 0.31vw, o sea menos de medio píxel de diferencia en todo el
     rango. Un token que no se distingue del de al lado no es una escala, es
     ruido: obliga a elegir entre dos cosas idénticas cada vez que se escribe
     una regla. Ahora --fs-h4 es un alias explícito de --fs-lead, así que los
     dos nombres siguen funcionando pero hay UN solo valor que mantener. */
  --fs-lead:    clamp(1.0625rem, 0.99rem + 0.31vw, 1.1875rem); /* 17 → 19 */
  --fs-h4:      var(--fs-lead);
  --fs-body:    1rem;
  --fs-sm:      0.9375rem;
  --fs-xs:      0.8125rem;
  --fs-eyebrow: 0.75rem;

  --lh-tight:   1.08;
  --lh-snug:    1.18;
  --lh-normal:  1.45;
  --lh-relaxed: 1.62;

  --track-tight:   -0.022em;
  --track-snug:    -0.012em;
  --track-eyebrow:  0.22em;
  --track-label:    0.16em;
}

/* --------------------------------------------------------------------------
   5 · ESPACIO Y FORMA
   -------------------------------------------------------------------------- */
:root {
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;  --sp-4: 1rem;
  --sp-5: 1.25rem;  --sp-6: 1.5rem;   --sp-8: 2rem;     --sp-10: 2.5rem;
  --sp-12: 3rem;    --sp-14: 3.5rem;  --sp-16: 4rem;    --sp-20: 5rem;
  --sp-24: 6rem;

  --section-pad:  clamp(5.5rem, 3.2rem + 6.4vw, 9.5rem);   /* 88 → 152 */
  /* Aire entre dos secciones del MISMO tema, donde no hay corte de color ni
     costura que llene el hueco. Ver la regla de ritmo en base.css. */
  --section-pad-tight: clamp(3.5rem, 2rem + 4.2vw, 6rem);  /* 56 → 96 */
  --gap-grid:     clamp(1rem, 0.6rem + 1.1vw, 1.5rem);
  --container:    1200px;
  --container-narrow: 820px;
  --gutter:       clamp(1.25rem, 0.9rem + 1.1vw, 1.5rem);

  --radius-sm:   0.5rem;
  --radius:      0.75rem;
  --radius-lg:   1.25rem;
  --radius-xl:   1.75rem;
  --radius-pill: 999px;
}

/* --------------------------------------------------------------------------
   6 bis · EL PELO DEL CANTO DE VIDRIO — y por qué depende de la densidad
   El aro de las superficies de vidrio (components.css § 1) se dibuja con
   box-shadow: inset, o sea que su grosor se resuelve en PÍXELES FÍSICOS.

   A DPR 2 y para arriba, 1,2px son 2,4 físicos: dos filas sólidas más una al
   40%, y el ojo lee un pelo fino y parejo. Es el valor aprobado y se queda.

   A DPR 1 —un monitor común a 100% de zoom— esos mismos 1,2px son 1,2 filas:
   UNA sólida y una segunda al 20%. Esa segunda fila es un fantasma que no
   aporta forma y desenfoca la línea entera. Medido a 14× sobre el canto recto
   de la isla: a 1,2px el borde sale doble y blando; a 1px sale UNA sola fila
   sólida y nítida, con el mismo brillo.
   No es una preferencia: por debajo de 2dppx no hay píxeles para gastar en
   una fila a medio encender, así que el pelo se clava en 1.
   -------------------------------------------------------------------------- */
:root { --hairline: 1.2px; }
@media (max-resolution: 1.9dppx), (-webkit-max-device-pixel-ratio: 1.9) {
  :root { --hairline: 1px; }
}


/* --------------------------------------------------------------------------
   6 ter · LOS CORTES — la escala de anchos del sitio (45ª pasada)

   ⚠ ESTO ES UNA TABLA EN UN COMENTARIO Y NO UNA LISTA DE CUSTOM PROPERTIES,
   y no es pereza: UN @media NO PUEDE LEER UN var(). No existen tokens de
   breakpoint en CSS sin un paso de build, y este proyecto es sin build a
   propósito. Entonces la fuente de verdad es esta tabla, y los literales de
   cada hoja apuntan acá. Mismo criterio que el registro de capas de la § 7.

   LA ESCALA DE LA CASA — cuatro escalones y uno medido:

     480px   teléfono chico          xs
     640px   teléfono → grande       sm   ← el más usado del sitio
     768px   tablet vertical         md
    1024px   escritorio              lg
    ( 860px  el corte de la bobina de testimonios — ver abajo )

   POR QUÉ 640 Y NO OTRO: es el que ya gobierna 15 reglas. La escala se eligió
   sobre lo que el sitio YA hacía, no sobre una tabla de dispositivos.

   TRES CORTES QUE NO ENTRAN A LA ESCALA, Y CADA UNO TIENE SU MOTIVO:

   · 860px — donde la bobina de testimonios deja de entrar en dos columnas
     (sections.css § 07). Es un corte MEDIDO SOBRE CONTENIDO, no un tamaño de
     dispositivo. Mientras la cita no cambie, el corte no cambia.

   · 480px — nació de un bug puntual y verificado (el índice de la card de
     proyectos se cruzaba con la etiqueta del placeholder, sections.css § 04) y
     se quedó como el escalón de teléfono chico.

   · 991 / 767 / 479 — ⚠ SON DE OTRO SISTEMA Y SE QUEDAN COMO ESTÁN.
     Son los cortes de Bruma, y viven en nosotros.css (que es un calco
     deliberado de brumalab) y en el token --borde de components.css § 14.
     Normalizarlos a 1024/768/480 MOVERÍA LOS BLOQUES respecto del original que
     esa página está copiando, que es exactamente lo que el comentario de
     nosotros.css:36 existe para impedir. El costo es un desfasaje de 1px
     —a 768 exactos aplica el bloque de la casa pero no el de Bruma— y está
     aceptado y acotado a esa hoja. No “arreglarlo”.

   DÓNDE SE PRUEBA: 320 · 360 · 390 · 768 · 1024 · 1440 · 1920 · 2560.
   Los dos primeros los agregó la 45ª y encontraron desborde donde 390 no veía
   nada. El último tampoco es opcional: un carrusel cuyo contenido entra entero
   en pantalla es un carrusel roto, y eso recién aparece arriba de 2400 (27ª).
   Con claude/verificacion/anchos3.mjs, que además dice QUÉ elemento desborda.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   6 · MOVIMIENTO
   -------------------------------------------------------------------------- */
:root {
  --ease-out:    cubic-bezier(.22, 1, .36, 1);
  --ease-expo:   cubic-bezier(.16, 1, .30, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  --ease-inout:  cubic-bezier(.65, 0, .35, 1);

  --dur-fast:   180ms;
  --dur:        320ms;
  --dur-slow:   640ms;
  --dur-reveal: 900ms;

  --stagger: 70ms;
}

/* --------------------------------------------------------------------------
   7 · CAPAS
   -------------------------------------------------------------------------- */
:root {
  --z-base: 1;
  --z-grain: 5;
  /* Cursor propio: arriba del grano (si no, el ruido lo apaga) y abajo del
     nav — la pastilla sigue al puntero por toda la ventana y no puede
     taparle la barra al usuario. */
  --z-cursor: 30;
  /* Botón flotante de WhatsApp (components.css § 15). Va ENTRE el cursor y el
     nav, y las dos fronteras están elegidas:
     · arriba del cursor (30) — la pastilla que sigue al puntero es una capa de
       información y tiene pointer-events: none; pasarle por debajo a un botón
       real la dejaría dibujada ENCIMA de algo que se puede tocar.
     · abajo del nav (40) y del menú (60) — el menú móvil es opaco y a pantalla
       completa, así que lo tapa solo, sin una regla que lo esconda a mano. */
  --z-wsp: 35;
  --z-nav: 40;
  --z-menu: 60;
  /* 100 · .skip-link (en base.css, sin token)
     120 · #obs-loader, el diafragma. NO tiene token a propósito: su CSS es
           inline en el <head> de index.html y no puede depender de este
           archivo, así que el número va literal allá. Se anota acá para que
           el registro de capas siga siendo completo. */
}
