{# Cellular star chart — v0.3.0 visual refresh.

   Replaces the prior floating-text header (translate(100,50) + translate(820,80))
   with a deliberate HUD-style header band: a solid rect at y=0..header_band_height
   filled with the variant's header_band tone, hosting the repo identifier,
   STAR HISTORY title, hero metric, and CURRENT STARS subtitle. The band reads
   as a separate visual zone, lifting header text out of the cell substrate
   instead of overlaying it.

   Cell substrate uses cells under the bezier polygon plus dormant cells
   across the full viewport. Cell stride is 19 (cell width 18, 1px gap),
   yielding a denser 30-col × 13-row grid in the chart area. Animation
   classes consolidate to b1/b2/b3/b4.

   Polyline drops to 3px white with double-glow drop-shadow (info_accent
   outer halo + tight white inner glow). Axis lines render at info_accent
   opacity 0.25 (was 0.14); gridlines stay faint at 0.06.

   Footer simplifies to a thin hairline + repo URL (left) + brand stamp
   (right) — the prior compound "HYPERWEAVE · STAR HISTORY" footer text is
   gone since the header band already states the chart class. #}

{% set _surface = surface_0 | default('var(--dna-surface)') %}
{% set _accent = chart_info_accent %}
{% set chart_levels = cellular_palette.primary.chart_levels %}

{# Outer rounded-corner clip wraps the entire chart so the background, header
   band, cells, polyline, and footer all clip to the same rx=10 silhouette.
   Without this wrapping group the chart reads as a flat rectangle; with it
   the chart frame becomes a deliberate artifact with curvature. The closing
   </g> sits at the very bottom of the template just before the optional
   outer border. #}
<g clip-path="url(#{{ uid }}-clip)">

{# Void ground — pure surface color, no cell substrate. #}
<rect width="{{ chart_layout.width }}" height="{{ chart_layout.height }}" fill="{{ _surface }}"/>

{# HEADER BAND (y=0..header_band_height). Vertical gradient from canvas_top
   to canvas_bottom — same material language as the stat card's header
   (cellular-content stats:33-36). The earlier flat `header_band` fill read
   as a distinct horizontal band against the canvas, especially on warmer
   tones (bone, amber); the gradient blends seamlessly while preserving the
   info_accent hairline at the bottom edge as the visible boundary. The
   header_band tone primitive stays in the genome for other consumers (icon
   cell grid). All text inside the band routes through the HUD filter so
   labels lift from the gradient fill. #}
<g data-hw-zone="header-band">
  <rect x="{{ chart_layout.rects.cellular_header_band.x }}" y="{{ chart_layout.rects.cellular_header_band.y }}"
        width="{{ chart_layout.rects.cellular_header_band.w }}" height="{{ chart_layout.rects.cellular_header_band.h }}"
        fill="url(#{{ uid }}-top-grad)"/>
  <line x1="{{ chart_layout.lines.cellular_header_rule.x1 }}" y1="{{ chart_layout.lines.cellular_header_rule.y1 }}"
        x2="{{ chart_layout.lines.cellular_header_rule.x2 }}" y2="{{ chart_layout.lines.cellular_header_rule.y2 }}"
        stroke="{{ _accent }}" stroke-opacity="0.12" stroke-width="0.5"/>
</g>
{# Header text positions tune the two pairs for VISIBLE-GAP coherence,
   not strict pair-center or baseline-shared alignment. Forcing both pairs
   to center at the same y created cramping (right pair's hero/subtitle
   visible gap collapsed to 2px, dominating user feedback). Forcing
   shared bottom baselines also stretched the left gap and crammed right.
   The cleaner solution: equal *visible* gaps between text blocks on each
   side, accepting that pair centers will differ slightly because the
   17px title and 34px hero have asymmetric cap heights.

   Visible gaps (text-bottom of upper row to text-top of lower row):
     - Left:  10px  (repo baseline 22 to title cap-top 32 = 10)
     - Right: 12px  (hero baseline 36 to subtitle cap-top 48 = 12)

   The right side gets a slightly wider gap because the dominant 34px hero
   benefits from extra breathing room before the small subtitle starts —
   matches the v2 prototype's same proportions (hero y=32, subtitle y=50,
   18 baseline / 12 visible gap). #}
{# v0.3.12-fix: NO HUD filter on the header text. The header band (above) already
   backs these labels for legibility — the same way the stat-card header sits on
   its band with no filter. Applying the feGaussianBlur HUD halo here forced the
   browser to rasterize the glyphs into a filter buffer, which softens on mobile
   (device-pixel-ratio handling) while the unfiltered stat-card header stays
   crisp. The HUD filter is retained ONLY on the axis / milestone / footer labels
   below, which sit directly on the cell substrate with no band. #}
<g data-hw-zone="header-text">
  <text x="{{ chart_layout.texts.cellular_repo.x }}" y="{{ chart_layout.texts.cellular_repo.y }}" class="{{ uid }}-hdr-user">{{ chart_repo | default('repo') | upper }}</text>
  <text x="{{ chart_layout.texts.cellular_title.x }}" y="{{ chart_layout.texts.cellular_title.y }}" class="{{ uid }}-title-main">{{ chart_series_title | default('STAR HISTORY') }}</text>
  <text x="{{ chart_layout.texts.cellular_hero_value.x }}" y="{{ chart_layout.texts.cellular_hero_value.y }}" class="{{ uid }}-hero-value" text-anchor="{{ chart_layout.texts.cellular_hero_value.anchor }}">{{ chart_current_stars | default('--') }}</text>
  <text x="{{ chart_layout.texts.cellular_hero_label.x }}" y="{{ chart_layout.texts.cellular_hero_label.y }}" class="{{ uid }}-hero-label" text-anchor="{{ chart_layout.texts.cellular_hero_label.anchor }}">{{ chart_hero_label | default('CURRENT STARS') }}</text>
</g>

{# CHART zone — layered render order: dormant (full viewport, no anim) →
   active cells (clipped to bezier polygon, animated) → gridlines → polyline
   → markers → milestones → axes. The dormant layer renders first so the
   active layer's clipped cells override it inside the polyline area. #}
<g data-hw-zone="chart">
  {%- if cellular_dormant_cells %}
  <g data-hw-zone="cellular-dormant">
    {%- for c in cellular_dormant_cells %}
    <rect x="{{ c.x }}" y="{{ c.y }}" width="{{ c.w }}" height="{{ c.h }}" fill="{{ c.fill }}"/>
    {%- endfor %}
  </g>
  {%- endif %}

  {%- if cellular_area_cells %}
  <g data-hw-zone="cellular-area" clip-path="url(#{{ uid }}-area-clip)">
    {%- for c in cellular_area_cells %}
    <rect x="{{ c.x }}" y="{{ c.y }}" width="{{ c.w }}" height="{{ c.h }}" fill="{{ c.fill }}" class="{{ c.anim_class }}"/>
    {%- endfor %}
  </g>
  {%- endif %}

  {# Gridlines — uniform faint hairlines tinted info_accent at 0.06 opacity. #}
  {%- for gl in chart_gridlines %}
  <line x1="{{ gl.x1 }}" y1="{{ gl.y1 }}" x2="{{ gl.x2 }}" y2="{{ gl.y2 }}" class="hw-chart-gridline"/>
  {%- endfor %}

  {# Polyline — 3px white core with double-glow drop-shadow (info_accent outer
     + tight white inner). Bezier (round linejoin) for cellular. #}
  {%- if chart_polyline %}
    {%- if chart_polyline.kind == 'path' %}
  <path d="{{ chart_polyline.d }}" class="hw-chart-line" fill="none"/>
    {%- else %}
  <polyline points="{{ chart_polyline.points }}" class="hw-chart-line" fill="none"/>
    {%- endif %}
  {%- endif %}

  {# Markers — smooth color progression along curve, white stroke + tinted
     drop-shadow. Endpoint matches the regular marker geometry exactly so it
     reads as the line's natural completion rather than a competing focal
     element. The cellular substrate under the curve does the visual talking;
     markers are structural beats, not exclamation points.

     Endpoint differences from regular markers:
       * fill = chart_levels[5] (brightest tier) so the terminal point feels
         like the apex of the marker color progression
       * NO animation class — pulse on the terminal point fights the line's
         natural flow into its endpoint #}
  <g data-hw-zone="markers" shape-rendering="geometricPrecision">
  {%- for m in chart_markers %}
    {%- if m.is_endpoint %}
    {%- set _fill = chart_levels[5] %}
    <g transform="translate({{ m.x }},{{ m.y }})">
      <rect x="{{ m.cellular_neg_half }}" y="{{ m.cellular_neg_half }}" width="{{ m.size }}" height="{{ m.size }}" transform="rotate(45 0 0)"
            fill="{{ _fill }}" stroke="var(--dna-chart-marker-stroke, var(--dna-ink-primary))" stroke-width="1"
            filter="drop-shadow(0 0 5px {{ _fill }})"/>
    </g>
    {%- else %}
    {%- set _fill = chart_levels[0] %}
    <g transform="translate({{ m.x }},{{ m.y }})">
      <rect x="{{ m.cellular_neg_half }}" y="{{ m.cellular_neg_half }}" width="{{ m.size }}" height="{{ m.size }}" transform="rotate(45 0 0)"
            fill="{{ _fill }}" stroke="var(--dna-chart-marker-stroke, var(--dna-ink-primary))" stroke-width="1"
            filter="drop-shadow(0 0 5px {{ _fill }})"/>
    </g>
    {%- endif %}
  {%- endfor %}
  </g>

  {# Milestone markers (vertical dashed lines + value labels at threshold
     crossings). #}
  <g data-hw-zone="milestones" filter="url(#{{ uid }}-hud)">
  {%- for ms in chart_milestones %}
    {%- include "components/chart-milestone.svg.j2" %}
  {%- endfor %}
  </g>

  {# Axes rails. #}
  {%- for ax in chart_axes %}
    {%- include "components/chart-axes.svg.j2" %}
  {%- endfor %}

  {# Empty-state overlay (fresh repo / upstream failure). #}
  {%- if chart_empty_state %}
    {%- include "components/chart-empty-state.svg.j2" %}
  {%- endif %}
</g>

{# Y-axis labels — HUD-filtered so they read against any cell bloom on the
   left edge of the chart. #}
<g data-hw-zone="y-axis" filter="url(#{{ uid }}-hud)">
  {% for label in chart_y_labels %}
  <text class="{{ uid }}-axis-y" x="{{ label.x }}" y="{{ label.y }}" text-anchor="{{ label.anchor }}">{{ label.text }}</text>
  {% endfor %}
</g>

{# X-axis — year labels below the chart. #}
<g data-hw-zone="x-axis" filter="url(#{{ uid }}-hud)">
  {% for label in chart_x_labels %}
  <text class="{{ uid }}-axis-x" x="{{ label.x }}" y="{{ label.y }}" text-anchor="{{ label.anchor }}">{{ label.text }}</text>
  {% endfor %}
</g>

{# FOOTER — thin hairline above + repo URL (left, mid_accent quiet) + brand
   stamp (right, info_accent very quiet). The chart class label is gone —
   the header band already establishes "STAR HISTORY" so the footer doesn't
   restate it. #}
<line x1="{{ chart_layout.lines.cellular_footer_rule.x1 }}" y1="{{ chart_layout.lines.cellular_footer_rule.y1 }}"
      x2="{{ chart_layout.lines.cellular_footer_rule.x2 }}" y2="{{ chart_layout.lines.cellular_footer_rule.y2 }}"
      stroke="{{ _accent }}" stroke-opacity="0.06" stroke-width="0.5"/>
<g data-hw-zone="footer" filter="url(#{{ uid }}-hud)">
  <text x="{{ chart_layout.texts.cellular_footer_url.x }}" y="{{ chart_layout.texts.cellular_footer_url.y }}" class="{{ uid }}-foot">{{ chart_subject_url | default(chart_repo | default('')) }}</text>
  <text x="{{ chart_layout.texts.cellular_footer_brand.x }}" y="{{ chart_layout.texts.cellular_footer_brand.y }}" class="{{ uid }}-foot-brand" text-anchor="{{ chart_layout.texts.cellular_footer_brand.anchor }}">HYPERWEAVE</text>
</g>

</g>{# end outer rounded-corner clip #}

{# Outer border — rounded rect tracing the chart's rx=10 silhouette in
   info_accent at very low opacity. Drawn OUTSIDE the clip group so the
   stroke isn't itself clipped at the corners. Reads as a deliberate
   artifact edge framing the composition. #}
<rect x="{{ chart_layout.cellular_outer_rect.x }}" y="{{ chart_layout.cellular_outer_rect.y }}"
      width="{{ chart_layout.cellular_outer_rect.w }}" height="{{ chart_layout.cellular_outer_rect.h }}"
      rx="{{ chart_layout.cellular_outer_rect.rx }}" fill="none" stroke="{{ _accent }}" stroke-opacity="0.10" stroke-width="1"/>
