On touch devices, tapping an eye button in the details panel would
trigger chart mouseout → showDefaultView() which rebuilt the DOM
before the click event fired. Added pointerdown/pointerup guards
on the details box to prevent the race condition.
Also added @media (pointer: coarse) to always show eye buttons
on touch devices regardless of viewport width.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Center donut at 50% for compact landscape phones (was ~47%, misaligned
with CSS center-label)
- Show eye buttons on touch devices via @media (pointer: coarse)
- Reduce right padding to 34px, narrow chart-wrapper to 49%
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace safe-area-inset padding with fixed 42px right / 24px left
(safe-area was 59px on both sides of iPhone Pro Max, too aggressive)
- Move center-label/eye-button hiding to height-based media query
covering all landscape phones, not just >851px
- Add compact h1 (24px), smaller month-preview donuts (28px) for
larger landscape phones
- Server: add Cache-Control: no-cache, strip query strings from URLs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Just env(safe-area-inset-*) with 8px fallback — no extra base padding
on top. The inset values already provide sufficient clearance.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
20px + safe-area was too much — the inset alone provides Dynamic Island
clearance, only need minimal base padding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Chart wrapper 52% (was 58%) for visual separation from details box
- Container padding 20px + safe-area-inset on both sides to clear
Dynamic Island in landscape
- Details box right offset includes safe-area-inset-right
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
For viewports >850px wide but <=500px tall (landscape):
- Hide center label text (month/amount), keep home icon on drill-down
- Wider details panel (40vw), smaller fonts (12-13px)
- Tighter spacing to fit all content without clipping
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
iPhone 17 Pro Max landscape is 956px wide, above the previous 950px
label threshold. Use isCompact flag instead of isMobile for hiding
level 3 outside labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
iPhone 17 Pro Max landscape viewport is ~956px wide, above the 850px
threshold. Use height <= 500px instead to detect all landscape phones
regardless of width.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move timeline legend from vertical top-right to horizontal bottom on portrait phones (<=850px + portrait)
- Landscape phones and tablets use desktop layout (vertical legend on right)
- CSS: cap chart-wrapper height with min(Xvw, calc(100dvh - 130px)) to prevent landscape overflow
- CSS: timeline-mode fills viewport height in portrait for better space utilization
- Rotate x-axis month labels to -90° on mobile for cleaner vertical display
- Add debounced resize handler to re-render on orientation/breakpoint changes
- Guard zrender click handler with y-bounds to prevent legend-zone false positives
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract resetLegendSelection into a reusable function exposed via
window._timelineResetLegend, allowing both the reset button click
and the Escape key handler to clear legend filtering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support DATA_DIR env var for configurable CSV directory,
add docker-compose.yml and .dockerignore for containerized hosting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Support 3-level drill: category → subcategory → microcategory
- Integrate browser back/forward with drill path and legend selection state
- Cmd-click isolates single series, Opt-click toggles series off
- Dynamic total labels update to reflect only visible series
- Add "Очистить" reset button when series are filtered
- Click month labels to switch to that month's donut view
- Persist timeline drill path in localStorage across reloads
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move legend from bottom to vertical top-right box with background
- Highlight hovered category in legend (bold text, others dimmed)
- Dim legend color swatches to 0.15 opacity for non-hovered items
- Make drill-down title larger (22px bold centered)
- Reserve right margin (180px) for legend, free up bottom space
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add drill-down into subcategories when clicking a category bar
- Use native ECharts emphasis/blur for category highlighting (focus: series)
- Show per-category labels on all bars via dispatchAction highlight
- Display total sum labels (к) above bars, ₽ on y-axis only
- Add color legend at bottom of chart
- Increase font sizes and angle x-axis labels for readability
- Remove details panel from timeline mode
- Clean up label management: no manual setOption race conditions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a second visualization mode showing spending across all months
as a stacked bar chart, with a месяц/таймлайн switcher in the header.
Includes side panel with category breakdowns, bar click-to-drill,
and localStorage persistence of the selected view.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cmd/Ctrl+click: toggle individual months in/out of selection
- Shift+click: select contiguous interval from current to clicked month
This matches standard selection behavior in file managers and lists.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Hold Shift and click months to select multiple, showing aggregated
spending data. Normal click resets to single month selection.
Cannot deselect the last remaining month.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Home icon only appears on narrow screens (≤850px), not desktop
- Added white circular background with subtle shadow for readability
- Icon is larger (28px + padding) for easier touch targeting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Home icon appears in center only when at least one level deep
- Clicking the icon navigates back to root view
- On narrow screens (≤850px), shows only the home icon (label hidden)
- Black/white styling with hover effect
- Works on both desktop and mobile/touch devices
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use !important to ensure chart eye btn is hidden on narrow (≤850px)
- Always show eye buttons in details panel on narrow layouts (opacity 0.5)
- Touch devices don't have hover, so eyes need to be visible by default
- Desktop (>850px) retains hover behavior for eye icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Smaller font sizes on mobile (10px/9px vs 13px/11px on desktop)
- Bolder font weight on mobile (600) for better readability
- Hide chart eye icon on narrow/stacked layouts (≤850px)
- Center chart at 50% when layout is stacked (≤850px)
- Dynamic font size/weight updates on resize
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Scale chart layers on mobile (≤500px) to fill container while
keeping same hole size as desktop (20%)
- Add resize handler to dynamically update proportions when crossing
500px threshold
- Hide center label at 850px (stacked layout) instead of 500px to
prevent overlap with chart
- Center chart at 50% on mobile since details box is below
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Hide center label on screens ≤500px (redundant with details box)
- Increase chart height to 95vw (500px) and 98vw (400px)
- Reduce container padding to minimize white space
- Adjust details box margin and max-height calculation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 500px breakpoint: smaller fonts, tighter spacing, smaller
month buttons and previews, center label adjustments
- Add 400px breakpoint for iPhone 13 (390px): even smaller fonts,
reduced padding, compact details box styling
- Title now fits on one line at all mobile sizes
- Month navigator buttons all visible without cutoff
- Center label scales appropriately for small screens
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use calc() to set details box max-height based on remaining viewport
space after chart (90lvw) and header (~140px). This prevents page
scrolling when hovering items with many subcategories - the details
box scrolls internally instead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allow details box to show all categories instead of being cut off
at 300px height on mobile/narrow screens.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
At 1200px and below, reduce chart width to 60% and increase details
box width to 38% (min 340px) to prevent amounts from being truncated.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added chart-wrapper div to contain both chart-container and center-label,
allowing the center-label to be positioned relative to the chart area
regardless of the overall layout (side-by-side or stacked).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move center label from ECharts canvas to HTML overlay for better font rendering
- Style ₽ symbol separately with lighter color (#888) and slightly smaller size (20px)
- Use tighter line height (1.0) for center label
- Remove "Детали" heading from details box, use total as header
- Remove top border from details header
- Increase header font sizes to 20px
- Add more whitespace above "Top Items:"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add formatRUB() helper that formats amounts without decimals and uses
U+202F (narrow no-break space) as thousands separator and before ₽ symbol.
This prevents unwanted line breaks within currency amounts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Clicking on the already-selected month button now returns to root
view when drilled down, providing a quick way to reset the chart
without using browser back or center click.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bug A: Center click to go back now works after switching months while
drilled down. Fixed by saving root state BEFORE drilled state in
selectMonth, so historyIndex=0 always points to root.
Bug B: Unknown subcategories (not in December data) now get distinct
colors. Fixed by tracking unknownCount separately and using
(predefinedCount + unknownIndex) % 10 to assign colors starting after
the predefined palette positions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add subcategoryOrder derived from subcategoryColors
- Add sortBySubcategoryOrder helper function
- Update click handler, transformDrillDownData, and mini-chart gradient
to use fixed order instead of value-based sorting
- Update details box to preserve fixed order for drilled-down views
while keeping value-based sorting for root level categories
This ensures subcategories maintain consistent positions when switching
months, even when their values differ (e.g., "Хобби Залины" always comes
before "Подписки" regardless of which has higher spending that month).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add fixed subcategory color mapping based on December 2025 data
- Update click handler and transformDrillDownData to use getSubcategoryColor
- Rotate mini-charts 90° clockwise to match main chart orientation
- Change month selector active state from blue to neutral gray (#4a4a4a)
- Ensure colors stay consistent when switching months while drilled down
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add currentDrillPath to track category hierarchy during drill-down
- Mini-charts now update to show the same category breakdown when
drilling into a category on the main chart
- Switching months while drilled down preserves the category path,
navigating to the same category in the new month
- Empty state shown for months that don't have the drilled category
- Browser back/forward navigation syncs mini-charts correctly
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Switch to SF Pro / system font stack for consistent ₽ rendering
- Apply font to both HTML and ECharts center text
- Reset chart highlight and details panel when closing modal
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Keep details panel showing sector info when hovering eye button
- Don't reset details when mouse moves from chart to eye button
- Close modals first when pressing browser back button
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Push drill-down states to browser history via history.pushState()
- Listen for popstate event to handle browser back/forward
- Mouse back/forward buttons and browser buttons now navigate drill-down
- Click center still works (calls history.back())
- Reset details panel when mouse leaves chart sector
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add custom column sorting (click headers to sort, click again to reverse)
- Add row click to open detail modal showing all transaction fields
- Row detail modal uses table layout with labels and values side by side
- Always show scrollbars, reset scroll position when modal opens
- Global escape key handler closes detail modal first, then main modal
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Set isInsideSection=true for all depth levels (1, 2, and others)
- Only reset to default view if not inside a section
- Prevents mouseout from resetting header when moving between sectors
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When clicking into a sector to drill down, the details header now shows
the sector name instead of the month name. The contextName parameter is
passed from the click handler to setupHoverEvents.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>