/* ============================================================
   OPEN WEIGHTS — "Open Enough"  (doodle 09)
   Derived from ocr.css by gen_ow_css.py — keep them in step.
   ------------------------------------------------------------
   doodles-base.css styles by class-name SUFFIX: [class$="-hero"],
   [class$="-title"], [class$="-visual"], [class$="-takeaways"], etc.
   Two consequences, both load-bearing:

   1. Page chrome gets styled for free ONLY if the class ends in the
      expected suffix. `.ocr-hero` works; `.ow-header` would render
      unstyled and look like a build failure.
   2. Any NEW class ending in one of those suffixes inherits heavy
      styling by accident. tokens.css hit this and had to override
      `.visual-title` / `.comparison-title` / `.sizes-title` after the
      import. This file sidesteps it instead: every in-SVG label class
      is named `.ocr-*` with a suffix base.css does not claim
      (-cap, -lbl, -num, -head, -glyph, -tiny). Do not rename one of
      them to `*-title` "for consistency" -- that is the bug.
   ============================================================ */
@import url('doodles-base.css?v=20260730b');

.open-weights-page {
  /* Map this doodle's palette onto the generic vars base.css reads. */
  --doodle-surface: var(--ow-surface);
  --doodle-surface-text: var(--ow-surface-text);
  --doodle-border: var(--ow-border);

  --ow-surface: #fff;
  --ow-surface-text: #000;
  --ow-border: #000;

  /* Same four hexes as tokens.css -- already contrast-checked on this
     site in both themes. A new palette would need its own axe pass. */
  --ow-accent-1: #DC2626;  /* Red   - misread / discarded */
  --ow-accent-2: #1D4ED8;  /* Blue  - pixels / raw input */
  --ow-accent-3: #16A34A;  /* Green - accepted output */
  --ow-accent-4: #D97706;  /* Amber - uncertainty */

  /* NOT #1D4ED8 (the value tokens.css uses). At full strength that blue is
     6.2:1 on this cream and passes, but doodles-base.css renders the sources
     box at 80% opacity, which drags the EFFECTIVE colour to #4970dd = 4.19:1
     and fails WCAG AA. Measured with axe, not estimated. #1E3A8A survives the
     same blend at 5.6:1. If you lighten this, re-run the axe pass. */
  --ow-link: #1E3A8A;
  --ow-link-hover: #15803D;

  --svg-text-label: 16px;
  --svg-text-body: 14px;
  --svg-text-small: 12px;
  --svg-text-tiny: 11px;
}

[data-theme="dark"] .open-weights-page {
  --ow-surface: #1a1a1a;
  --ow-surface-text: #f5f5f5;
  --ow-border: #444;
  --ow-link: #60A5FA;
  --ow-link-hover: #4ADE80;
  /* SVG accents need lifting in dark: the light values measure
     2.60:1 (blue) and 3.60:1 (red) on the #1a1a1a figure surface.
     axe does NOT check SVG <text>, so this never showed up as a
     violation — it is a readability bug, not a scan result. */
  --ow-accent-1: #F87171;
  --ow-accent-2: #60A5FA;
  --ow-accent-3: #4ADE80;
  --ow-accent-4: #FBBF24;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .open-weights-page {
    --ow-surface: #1a1a1a;
    --ow-surface-text: #f5f5f5;
    --ow-border: #444;
    --ow-link: #60A5FA;
    --ow-link-hover: #4ADE80;
    /* SVG accents need lifting in dark: the light values measure
       2.60:1 (blue) and 3.60:1 (red) on the #1a1a1a figure surface.
       axe does NOT check SVG <text>, so this never showed up as a
       violation — it is a readability bug, not a scan result. */
    --ow-accent-1: #F87171;
    --ow-accent-2: #60A5FA;
    --ow-accent-3: #4ADE80;
    --ow-accent-4: #FBBF24;
  }
}

.open-weights-visual svg {
  width: 100%;
  height: auto;
  display: block;
  /* The threshold ramp's outline uses stroke="currentColor", which resolves
     against `color` -- not against the `fill` set on .open-weights-visual text. Set
     it explicitly or that stroke falls back to the inherited body colour
     and stops tracking the theme. */
  color: var(--ow-surface-text);
}

.sources-list a,
.open-weights-cta-subtext a {
  color: var(--ow-link);
}
.sources-list a:hover,
.sources-list a:focus,
.open-weights-cta-subtext a:hover,
.open-weights-cta-subtext a:focus {
  color: var(--ow-link-hover);
}

/* base.css sets a font on [class$="-visual"] text; this wins on source
   order (imported above) so the mono stack applies inside the SVGs. */
.open-weights-visual text {
  font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;
  fill: var(--ow-surface-text);
}

/* ---------- in-SVG type scale ---------- */
.ow-head {
  font-size: var(--svg-text-label);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.ow-lbl {
  font-size: var(--svg-text-body);
  font-weight: 600;
}
.ow-cap {
  font-size: var(--svg-text-small);
  opacity: .78;
}
.ow-tiny {
  font-size: var(--svg-text-tiny);
  opacity: .7;
}
.ow-num {
  font-size: var(--svg-text-tiny);
  font-weight: 600;
}
.ow-glyph {
  font-size: 34px;
  font-weight: 700;
}

/* ---------- ink ----------
   SCOPED under .open-weights-visual on purpose. `.open-weights-visual text` sets a default
   fill at specificity (0,1,1); a bare `.ow-ink-1` is only (0,1,0) and
   would LOSE to it, silently rendering every accent-coloured label in the
   default foreground. Scoping lifts these to (0,2,0). If you ever move a
   rule out from under .open-weights-visual, the colour quietly stops applying. */
.open-weights-visual .ow-ink-1 { fill: var(--ow-accent-1); }
.open-weights-visual .ow-ink-2 { fill: var(--ow-accent-2); }
.open-weights-visual .ow-ink-3 { fill: var(--ow-accent-3); }
.open-weights-visual .ow-ink-4 { fill: var(--ow-accent-4); }

.open-weights-visual .ow-stroke-1 { stroke: var(--ow-accent-1); }
.open-weights-visual .ow-stroke-2 { stroke: var(--ow-accent-2); }
.open-weights-visual .ow-stroke-3 { stroke: var(--ow-accent-3); }
.open-weights-visual .ow-stroke-4 { stroke: var(--ow-accent-4); }

.ow-frame {
  fill: none;
  stroke: var(--ow-surface-text);
  stroke-width: 2;
}

/* Opaque variant, for boxes that sit ON a rule and must occlude it.
   MUST stay after .ow-frame -- equal specificity, source order wins. */
.ow-solid {
  fill: var(--ow-surface);
}
.ow-hair {
  fill: none;
  stroke: var(--ow-surface-text);
  stroke-width: 1;
  opacity: .45;
}
.ow-dash {
  fill: none;
  stroke-width: 2;
  stroke-dasharray: 5 4;
}

/* ---------- pixel-grid cells ----------
   Two classes rather than one class plus a fill="" attribute. Author CSS
   ALWAYS beats a presentation attribute, so `class="ocr-hair"` combined
   with `fill="currentColor"` would resolve to fill:none and every "on"
   cell would vanish. The state lives in the class, not the attribute. */
.ow-cell {
  fill: none;
  stroke: var(--ow-surface-text);
  stroke-width: 1;
  opacity: .4;
}
.ow-cell-on {
  fill: var(--ow-surface-text);
  stroke: var(--ow-surface-text);
  stroke-width: 1;
}

/* ---------- hero ---------- */
.open-weights-title {
  /* base.css [class$="-title"] carries the display sizing; only the
     line-height needs tightening for the two-line stack. */
  line-height: .88;
}

/* ---------- scroll-triggered reveal ----------
   base.css handles the [class$="-visual"] fade. These stagger the
   pieces INSIDE each figure. Every rule is gated on .animate-in so a
   reduced-motion visitor (ocr.js adds the class immediately, skipping
   the observer) still sees the finished state. */
.ow-step {
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .45s ease, transform .45s ease;
}
.open-weights-visual.animate-in .ow-step { opacity: 1; transform: translateY(0); }
.open-weights-visual.animate-in .ow-step:nth-of-type(2) { transition-delay: .10s; }
.open-weights-visual.animate-in .ow-step:nth-of-type(3) { transition-delay: .20s; }
.open-weights-visual.animate-in .ow-step:nth-of-type(4) { transition-delay: .30s; }
.open-weights-visual.animate-in .ow-step:nth-of-type(5) { transition-delay: .40s; }
.open-weights-visual.animate-in .ow-step:nth-of-type(6) { transition-delay: .50s; }

.ow-sweep {
  opacity: 0;
  transition: opacity .5s ease .35s;
}
.open-weights-visual.animate-in .ow-sweep { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .ow-step,
  .ow-sweep {
    opacity: 1;
    transform: none;
    transition: none;
  }
}
