@charset "UTF-8";

/*
  redKAOS tools — base.css

  Kubuntu Breeze palette + shared typography + tool-pattern components.
  Vive aquí como single source of truth — Caddy lo sirve a las 5
  subdomains vía el snippet (shared_assets) que mapea /style/* a este
  directorio. No hay copia per-tool. Ver CSS-REDESIGN-BRIEF.md para
  los patrones HTML que asume.

  Tipografía: Nimbus Mono (h1) + Ubuntu (prosa) + Ubuntu Mono (técnico).
  Fuentes autohospedadas bajo /font/, subseteadas a Español + Inglés
  con scripts/optimize-fonts.py.
  Licencias en /font/UFL.txt (Ubuntu) y /font/GFL.txt (TeX Gyre Cursor).
  Modificaciones de TeX Gyre Cursor en /font/MANIFEST-tex-gyre-cursor.txt.
*/

@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/font/ubuntu-regular.woff2?h=cd929062c0") format("woff2");
}

@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/font/ubuntu-bold.woff2?h=6dd11bb419") format("woff2");
}

@font-face {
  font-family: "Ubuntu Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/font/ubuntu-mono-regular.woff2?h=8d293080f7") format("woff2");
}

/* Nimbus Mono (TeX Gyre Cursor): typewriter monoespaciada de redKAOS
   desde 2004. Reemplaza el paréntesis Hepta Slab Thin (2026-04 → 2026-05)
   para realinear con el portal. Ver MANIFEST en /font/. */
@font-face {
  font-family: "Nimbus Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/font/nimbus-mono-regular.woff2?h=9737aedbbd") format("woff2");
}

/* ─── Design tokens (Kubuntu Breeze) ───────────────────────────── */

:root {
  --bg: #232627;
  --text: #fcfcfc;
  --muted: #7f8c8d;
  --accent: #11D116;
  --rule: #3a3e40;
  --panel: #1a1d1e;

  --font-sans: "Ubuntu", system-ui, -apple-system, sans-serif;
  --font-mono: "Ubuntu Mono", ui-monospace, Menlo, Consolas, monospace;
  --font-title: "Nimbus Mono", "Courier New", monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.6 var(--font-sans);
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

/* ─── Layout ──────────────────────────────────────────────────── */

.page {
  max-width: 68ch;
  margin: 0 auto;
  padding: 3em 1.5em 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  flex: 1 0 auto;
}

/* ─── Breadcrumb (vuelta al hub) ──────────────────────────────── */

.breadcrumb {
  font-family: var(--font-mono);
  font-size: 0.85em;
  color: var(--muted);
  margin: 0 0 2em;
}

.breadcrumb a {
  color: var(--muted);
  text-decoration: none;
}

.breadcrumb a:hover { color: var(--accent); }

.breadcrumb .sep {
  color: var(--rule);
  margin: 0 0.5em;
}

/* ─── Header ──────────────────────────────────────────────────── */

header {
  border-bottom: 1px solid var(--rule);
  padding-bottom: 1.5em;
  margin-bottom: 2em;
}

h1 {
  color: var(--accent);
  font-family: var(--font-title);
  font-size: 5em;
  font-weight: 400;
  letter-spacing: -0.1em;
  margin: 0 0 0.2em;
  line-height: 1;
}

.lema {
  margin: 0;
}

/* ─── Hero (dato central de la tool) ──────────────────────────── */

.hero {
  text-align: center;
  padding: 2.5em 0 2em;
}

.hero-label {
  font-family: var(--font-mono);
  font-size: 0.75em;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.15em;
  margin: 0;
}

.hero-value {
  font-family: var(--font-mono);
  font-size: 2.6em;
  color: var(--accent);
  letter-spacing: 0.02em;
  margin: 0.4em 0;
  word-break: break-all;
  line-height: 1.2;
}

.hero-context {
  font-family: var(--font-mono);
  color: var(--muted);
  font-size: 0.9em;
  margin: 0.8em 0 0;
}

.hero-context strong {
  color: var(--text);
  font-weight: normal;
}

/* Hero tests — pair of pass/fail markers used as hero value */
.hero-tests {
  display: flex;
  gap: 2em;
  justify-content: center;
  flex-wrap: wrap;
  margin: 0.8em 0;
  font-family: var(--font-mono);
  font-size: 1.1em;
}

.test {
  color: var(--muted);
}

.test--reject { color: var(--accent); }
.test--accept { color: var(--muted); }

/* ─── Explainer (prosa explicativa) ───────────────────────────── */

.explainer {
  margin: 2em auto;
}

.explainer p {
  margin: 0.8em 0;
  text-align: justify;
  hyphens: auto;
}

/* ─── Reveals panel (qué revela / implica / contiene) ─────────── */

.reveals {
  background: var(--panel);
  border: 1px solid var(--rule);
  padding: 1.2em 1.5em;
  margin: 2em 0;
}

.reveals h2,
.reveals h3 {
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.9em;
  font-weight: normal;
  text-transform: lowercase;
  letter-spacing: 0.05em;
  margin: 0 0 0.6em;
}

.reveals h2::before,
.reveals h3::before {
  content: "// ";
  color: var(--muted);
}

.reveals ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.reveals li {
  padding: 0.2em 0;
  font-size: 0.95em;
  text-wrap: pretty;
}

.reveals li::before {
  content: "→ ";
  color: var(--accent);
  font-family: var(--font-mono);
  margin-right: 0.3em;
}

/* Bisagra dentro del panel: separa dos grupos de bullets */
.reveals p {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.82em;
  margin: 0.9em 0 0.2em;
  letter-spacing: 0.02em;
}

/* ─── Related (cross-links a otras tools del ecosistema) ──────── */

.related {
  margin: 3em 0 2em;
}

.related h2 {
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 1em;
  font-weight: normal;
  text-transform: lowercase;
  letter-spacing: 0.05em;
  margin: 0 0 0.8em;
}

.related h2::before {
  content: "// ";
  color: var(--muted);
}

.related ul {
  list-style: none;
  padding: 0;
  margin: 0.8em 0;
}

.related li {
  padding: 0.25em 0;
  display: flex;
  gap: 1em;
  align-items: baseline;
}

.related ul a {
  color: var(--accent);
  text-decoration: none;
  font-family: var(--font-mono);
  min-width: 11ch;
  flex-shrink: 0;
}

.related ul a:hover { text-decoration: underline; }

.related li .desc {
  color: var(--muted);
  font-size: 0.9em;
}

/* ─── Links en prosa ──────────────────────────────────────────── */

a {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-underline-offset: 0.15em;
}

a:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}

/* ─── Code / output terminal-like ─────────────────────────────── */

code, pre, .mono {
  font-family: var(--font-mono);
}

/* Inline code: no background — the page already is the terminal.
   See "Box rule" in redkaos.net/IDENTITY.md. */
code {
  padding: 0.1em 0.35em;
  font-size: 0.92em;
}

/* Code block: transparent, delimited by a rule border + 2px radius. */
pre {
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 1em 1.2em;
  overflow-x: auto;
  font-size: 0.88em;
  line-height: 1.5;
}

pre code {
  padding: 0;
}

/* ─── Forms (para uridecoder y similares con input) ───────────── */

input[type="text"],
input[type="url"],
textarea {
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--rule);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 1rem;
  padding: 0.6em 0.8em;
  border-radius: 2px;
}

input[type="text"]:focus,
input[type="url"]:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent);
}

/* ─── Button (para tools interactivas) ───────────────────────── */

.btn {
  display: block;
  width: fit-content;
  margin-left: auto;
  margin-top: 0.6em;
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 0.85em;
  padding: 0.4em 1em;
  border-radius: 2px;
  cursor: pointer;
  text-transform: lowercase;
  letter-spacing: 0.05em;
}

.btn:hover {
  background: var(--accent);
  color: var(--bg);
}

.btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ─── Shell prompt + cursor (terminal-style easter egg) ──────── */

@keyframes blink { 50% { opacity: 0; } }

.prompt {
  color: var(--accent);
}

.cursor {
  color: var(--accent);
  animation: blink 1s step-end infinite;
}

@media (prefers-reduced-motion: reduce) {
  .cursor { animation: none; }
}

/* ─── Copyright footer (ecosystem signature) ─────────────────── */

footer.copy {
  display: flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 0.85em;
  color: var(--muted);
  letter-spacing: 0.05em;
  margin-top: 2em;
  padding-right: max(1.5em, env(safe-area-inset-right));
  padding-bottom: max(0.5em, env(safe-area-inset-bottom));
}

footer.copy > p {
  flex: 1;
  text-align: center;
  margin: 0.4em 0;
}

/* ─── Pi (bottom-right easter egg) ─────────────────────────────── */

a.pi {
  color: var(--muted);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 1em;
  line-height: 1;
}

/* ─── Status / state indicators (para donottrack privacy signals) */

.status {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.85em;
  padding: 0.2em 0.6em;
  border: 1px solid var(--rule);
  border-radius: 2px;
}

.status--on {
  border-color: var(--accent);
  color: var(--accent);
}

.status--off {
  color: var(--muted);
}

.status--deprecated {
  color: var(--muted);
  text-decoration: line-through;
}

/* ─── Map + marker (para geolocation) ────────────────────────── */
/* World is rendered as a grid of precomputed 8°×6° SVG tiles. The marker
   rides on an overlay spanning the same box; 4 line segments slide inward
   from each edge with overflow:hidden clipping the outside portions, so
   grow+travel reads as one continuous motion (see DESIGN.md in geolocation/). */

.map-wrap {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  margin: 2em auto;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: 2px;
  overflow: hidden;
}

.tile-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(6, 1fr);
  width: 100%;
  height: 100%;
}

.tile {
  display: block;
  position: relative;
  /* No overflow:hidden here on purpose. With 16:9 aspect + 6 rows, row
     boundaries land on fractional pixel positions (e.g. 67.5, 202.5,
     337.5 on a 405 px-tall map). overflow:hidden on each tile would clip
     the SVG bleed exactly at those sub-pixel lines → seams. Instead, the
     generator emits each tile's polygon clipped with a small inflated
     bbox (BLEED in scripts/generate-tiles.py) so adjacent tiles'
     overhangs overlap each other at the shared boundary. .map-wrap's
     own overflow:hidden still clips anything past the map edge. */
}

.tile svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  shape-rendering: geometricPrecision;
}

.tile .land { fill: var(--rule); }
.tile .border {
  fill: none;
  stroke: var(--bg);
  stroke-width: 1.2;          /* screen px — non-scaling-stroke keeps it readable at any tile size */
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* ─── Marker (geolocation point reveal) ──────────────────────── */
/* --mx, --my are set per-visit by main.js based on user coords. */

.marker {
  position: absolute; inset: 0;
  overflow: hidden;
  --mx: 50%;
  --my: 50%;
  --seg: 48px;
  pointer-events: none;
}

.marker .line {
  position: absolute;
  background: var(--accent);
}

/* Resting position: visible at the edge, ready to travel. Animations only
   apply when .marker.active is set — main.js toggles the class to
   restart the single-shot grow+travel+emerge sequence on every placement.

   2 px thickness (not 1 px) avoids sub-pixel fade-out at 100% zoom on
   displays where CSS px ≠ integer device px (e.g. macOS "more space"
   scaling). box-shadow adds a subtle glow to lift the line off dark
   tiles without thickening the visual weight. */

.marker .line.left,
.marker .line.right {
  top: var(--my);
  width: var(--seg);
  height: 1.2px;
  transform: translateY(-50%) scaleX(1);
  will-change: transform, left, right;
}

.marker .line.left {
  left: calc(0px - var(--seg));
  transform-origin: right center;
  --to-x: calc(var(--mx) - var(--seg));
}

.marker .line.right {
  left: 100%;
  transform-origin: left center;
  --to-x: var(--mx);
}

.marker .line.top,
.marker .line.bottom {
  left: var(--mx);
  width: 1.2px;
  height: var(--seg);
  transform: translateX(-50%) scaleY(1);
  will-change: transform, top, bottom;
}

.marker .line.top {
  top: calc(0px - var(--seg));
  transform-origin: center bottom;
  --to-y: calc(var(--my) - var(--seg));
}

.marker .line.bottom {
  top: 100%;
  transform-origin: center top;
  --to-y: var(--my);
}

.marker.active .line.left,
.marker.active .line.right {
  animation: marker-line-h 1.4s cubic-bezier(.55, .05, .35, 1) forwards;
}

.marker.active .line.top,
.marker.active .line.bottom {
  animation: marker-line-v 1.4s cubic-bezier(.55, .05, .35, 1) forwards;
}

@keyframes marker-line-h {
  55%  { left: var(--to-x); transform: translateY(-50%) scaleX(1); opacity: 1; }
  72%  { left: var(--to-x); transform: translateY(-50%) scaleX(0); opacity: 1; }
  100% { left: var(--to-x); transform: translateY(-50%) scaleX(0); opacity: 0; }
}

@keyframes marker-line-v {
  55%  { top: var(--to-y); transform: translateX(-50%) scaleY(1); opacity: 1; }
  72%  { top: var(--to-y); transform: translateX(-50%) scaleY(0); opacity: 1; }
  100% { top: var(--to-y); transform: translateX(-50%) scaleY(0); opacity: 0; }
}

.marker .core {
  position: absolute;
  left: var(--mx);
  top:  var(--my);
  width: 7px;
  height: 7px;
  background: var(--accent);
  border-radius: 50%;
  transform-origin: center center;
  /* translate3d forces the core onto its own compositing layer, which
     avoids sub-pixel re-rounding of translate(-50%,-50%) each time the
     box-shadow (and therefore the render box) changes during the
     infinite pulse. Paired with will-change so browsers keep the
     layer stable for the life of the marker. */
  transform: translate3d(-50%, -50%, 0) scale(0);
  opacity: 0;
  box-shadow: 0 0 0 2px var(--bg);
  will-change: transform, box-shadow, opacity;
  z-index: 2;
}

.marker.active .core {
  animation:
    marker-core-emerge 1.4s ease-out forwards,
    marker-core-pulse  2.4s ease-in-out 1.4s infinite;
}

/* Simplified: core grows from scale(0) to scale(1) in one pass, with the
   halo emerging alongside. No overshoot, no shrink-back — the pulse
   takes over from the final rest state. */
@keyframes marker-core-emerge {
  55%  { transform: translate3d(-50%, -50%, 0) scale(0); opacity: 0; }
  100% { transform: translate3d(-50%, -50%, 0) scale(1); opacity: 1;
         box-shadow: 0 0 0 2px var(--bg), 0 0 4px 1px var(--accent); }
}

/* Explicit transform in every keyframe prevents a sub-pixel snap when
   the infinite pulse takes over from the single-shot emerge — some
   browsers reconcile the two animations' transform contributions
   differently if pulse omits the property. */
@keyframes marker-core-pulse {
  0%, 100% {
    transform: translate3d(-50%, -50%, 0) scale(1);
    box-shadow: 0 0 0 2px var(--bg), 0 0 4px  1px var(--accent);
  }
  50% {
    transform: translate3d(-50%, -50%, 0) scale(1);
    box-shadow: 0 0 0 2px var(--bg), 0 0 14px 4px var(--accent);
  }
}

@media (prefers-reduced-motion: reduce) {
  .marker .line { animation: none; opacity: 0; }
  .marker .core {
    animation: none;
    transform: translate3d(-50%, -50%, 0) scale(1);
    opacity: 1;
    box-shadow: 0 0 0 2px var(--bg), 0 0 4px 1px var(--accent);
  }
}

/* ─── Data readout (label:value grid, mono) ───────────────────── */
/* Used by geolocation for postal/city/region/country/tz/sun-event rows.
   Reusable for future tools that surface structured facts. */

.data {
  font-family: var(--font-mono);
  color: var(--text);
  font-size: 0.95em;
  text-align: left;
  display: inline-block;
  margin: 0 auto;
  max-width: 100%;
}

.data-row {
  display: grid;
  grid-template-columns: 14ch 1fr;
  gap: 0.6em;
  padding: 0.2em 0;
}

.data-label { color: var(--muted); }
.data-value { color: var(--text); word-wrap: break-word; }

/* ─── Responsive ──────────────────────────────────────────────── */

@media (max-width: 480px) {
  .hero-value { font-size: 1.8em; }
  .related li {
    flex-direction: column;
    gap: 0.2em;
  }
  .related ul a { min-width: 0; }
  .data-row { grid-template-columns: 1fr; gap: 0; }
  .data-label { font-size: 0.85em; }
}
