visual-spending/styles.css
Anton Volnuhin 7e87a03b90 Fix home icon centering, eye icons on touch, tune landscape layout
- 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>
2026-02-08 00:48:50 +03:00

1112 lines
20 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background-color: #f5f5f5;
color: #333;
}
.container {
width: 100%;
margin: 0 auto;
padding: 20px;
padding-top: calc(20px + env(safe-area-inset-top));
}
.header {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 20px;
}
/* Month Navigator */
.month-navigator {
display: flex;
align-items: center;
gap: 8px;
max-width: 60%;
margin-left: auto;
}
.nav-arrow {
width: 36px;
height: 36px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: white;
font-size: 24px;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s, border-color 0.2s;
flex-shrink: 0;
}
.nav-arrow:hover:not(:disabled) {
background-color: #f0f0f0;
border-color: #999;
}
.nav-arrow:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.month-list {
display: flex;
gap: 6px;
overflow-x: auto;
scrollbar-width: none;
-ms-overflow-style: none;
}
.month-list::-webkit-scrollbar {
display: none;
}
.month-btn {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: white;
font-size: 14px;
cursor: pointer;
white-space: nowrap;
transition: background-color 0.2s, border-color 0.2s, color 0.2s;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
}
.month-btn:hover {
background-color: #f0f0f0;
border-color: #999;
}
.month-btn.active {
background-color: #4a4a4a;
border-color: #4a4a4a;
color: white;
}
.month-preview {
width: 40px;
height: 40px;
border-radius: 50%;
border: 1px solid #eee;
position: relative;
}
.month-preview::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 35%;
height: 35%;
background: white;
border-radius: 50%;
}
.month-btn.active .month-preview {
border-color: rgba(255, 255, 255, 0.3);
}
.month-btn.active .month-preview::after {
background: #4a4a4a;
}
.month-label {
font-size: 12px;
}
/* View switcher */
.view-switcher {
display: inline-flex;
gap: 4px;
}
.view-switcher-btn {
background: none;
border: none;
border-bottom: 2px solid transparent;
padding: 4px 8px;
font-size: 14px;
font-family: inherit;
color: #999;
cursor: pointer;
transition: color 0.2s, border-color 0.2s;
}
.view-switcher-btn:hover {
color: #666;
}
.view-switcher-btn.active {
color: #333;
border-bottom-color: #333;
}
/* Timeline mode modifiers */
.container.timeline-mode #center-label,
.container.timeline-mode #chart-eye-btn,
.container.timeline-mode #details-box {
display: none !important;
}
.container.timeline-mode .month-navigator {
display: none;
}
.container.timeline-mode .chart-wrapper {
width: 100%;
}
.content-wrapper {
display: flex;
position: relative;
}
.chart-wrapper {
position: relative;
width: 70%;
height: 80vh;
}
#chart-container {
width: 100%;
height: 100%;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
/* Center label overlay */
.center-label {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
text-align: left;
pointer-events: none;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", system-ui, sans-serif;
z-index: 10;
}
.center-month {
font-size: 18px;
font-weight: 400;
color: #666;
line-height: 1.0;
}
.center-category {
font-size: 18px;
font-weight: 600;
color: #333;
line-height: 1.0;
}
.center-category:empty {
display: none;
}
.center-home {
display: none;
justify-content: center;
pointer-events: auto;
cursor: pointer;
}
.center-home svg {
width: 32px;
height: 32px;
color: #333;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
padding: 8px;
transition: all 0.2s;
}
.center-home:hover svg {
color: #000;
background: #fff;
}
.center-amount {
font-size: 22px;
font-weight: 700;
line-height: 1.0;
}
.center-amount-num {
color: #000;
}
.center-rub {
color: #888;
font-size: 20px;
}
/* Override ECharts default pointer cursor - only eye button should have pointer */
#chart-container canvas {
cursor: default !important;
}
#details-box {
position: absolute;
top: 10px;
right: 10px;
width: 35vw;
min-width: 300px;
max-width: 650px;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.15);
padding: 20px;
z-index: 10;
min-height: auto;
max-height: 80vh;
overflow-y: auto;
opacity: 0.98;
border: 1px solid #eee;
margin-left: 0;
}
#details-box h3 {
margin-bottom: 15px;
color: #333;
font-size: 18px;
border-bottom: 1px solid #eee;
padding-bottom: 8px;
}
#details-box h4 {
margin: 18px 0 5px;
color: #555;
font-size: 14px;
}
.details-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.hover-name {
font-weight: bold;
color: #333;
word-break: break-word;
flex: 1;
display: flex;
align-items: center;
font-size: 20px;
}
.hover-amount {
font-size: 20px;
color: #0066cc;
font-weight: bold;
margin-left: 10px;
white-space: nowrap;
text-align: right;
min-width: 120px;
}
.color-circle {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 8px;
flex-shrink: 0;
}
#top-items {
font-size: 14px;
}
.top-item {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px dashed #eee;
}
.top-item:last-child {
border-bottom: none;
}
.top-item-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: flex;
align-items: center;
min-width: 0;
width: 50%;
flex-shrink: 0;
}
.top-item-amount {
margin-left: auto;
font-weight: bold;
min-width: 100px;
text-align: right;
flex-shrink: 0;
}
.top-item-percent {
margin-left: 8px;
width: 45px;
text-align: right;
flex-shrink: 0;
color: #999;
font-weight: 400;
}
/* Add responsive design for smaller screens */
@media (max-width: 1200px) {
.chart-wrapper {
width: 60%;
}
#details-box {
width: 38%;
min-width: 340px;
}
}
@media (max-width: 850px) {
.view-switcher {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 900;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: flex;
justify-content: center;
gap: 0;
padding: 8px 16px;
padding-bottom: calc(8px + env(safe-area-inset-bottom));
border-top: 1px solid #e0e0e0;
}
.view-switcher-btn {
flex: 1;
max-width: 160px;
padding: 8px 16px;
border-radius: 20px;
border-bottom: none;
font-size: 14px;
font-weight: 500;
text-align: center;
color: #666;
background: transparent;
}
.view-switcher-btn.active {
background: #333;
color: #fff;
border-bottom: none;
}
.container {
padding-bottom: calc(70px + env(safe-area-inset-bottom));
}
.header {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 15px;
}
.month-navigator {
max-width: 100%;
width: 100%;
}
.content-wrapper {
flex-direction: column;
}
.chart-wrapper {
width: 100%;
height: min(90lvw, calc(100dvh - 130px));
}
#details-box {
position: relative;
top: 0;
right: 0;
width: 100%;
margin-top: 15px;
max-height: calc(100vh - 90vw - 130px);
min-width: 100%;
overflow-y: auto;
}
.container.timeline-mode .chart-wrapper {
width: 100%;
height: calc(100dvh - 130px - env(safe-area-inset-bottom));
}
.top-item-amount {
min-width: 80px;
}
.center-label {
display: none;
}
/* Still show home icon on narrow screens when drilled down */
.center-label.drilled-down {
display: flex;
align-items: center;
justify-content: center;
}
.center-label.drilled-down .center-home {
display: flex;
}
.center-label.drilled-down .center-month,
.center-label.drilled-down .center-category,
.center-label.drilled-down .center-amount {
display: none;
}
.chart-eye-btn {
display: none !important;
}
}
@media (max-width: 500px) {
h1 {
font-size: 22px;
}
.month-btn {
padding: 4px 6px;
font-size: 11px;
}
.month-preview {
width: 28px;
height: 28px;
}
.month-label {
font-size: 9px;
}
.nav-arrow {
width: 28px;
height: 28px;
font-size: 18px;
}
.month-navigator {
gap: 4px;
}
.month-list {
gap: 4px;
}
.container {
padding: 15px 10px;
}
.chart-wrapper {
height: min(95vw, calc(100dvh - 130px));
}
#chart-container {
background-color: transparent;
box-shadow: none;
border-radius: 0;
}
}
@media (max-width: 400px) {
h1 {
font-size: 20px;
}
.container {
padding: 12px 8px;
}
.month-btn {
padding: 4px 5px;
}
.month-preview {
width: 26px;
height: 26px;
}
.nav-arrow {
width: 26px;
height: 26px;
font-size: 16px;
}
.chart-wrapper {
height: min(100vw, calc(100dvh - 130px));
}
.details-header {
padding: 8px 0;
}
.hover-name {
font-size: 16px;
}
.hover-amount {
font-size: 16px;
min-width: 100px;
}
#details-box h4 {
margin: 12px 0 5px;
font-size: 13px;
}
.top-item {
padding: 6px 0;
}
.top-item-name {
font-size: 13px;
}
.top-item-amount {
font-size: 13px;
min-width: 70px;
}
.top-item-percent {
font-size: 12px;
width: 40px;
}
}
/* Landscape phones: revert to desktop-like layout */
@media (max-width: 850px) and (orientation: landscape) {
h1 {
font-size: 20px;
white-space: nowrap;
}
.view-switcher {
position: static;
background: none;
backdrop-filter: none;
-webkit-backdrop-filter: none;
padding: 0;
border-top: none;
display: inline-flex;
gap: 4px;
flex-shrink: 0;
}
.view-switcher-btn {
flex: none;
max-width: none;
padding: 4px 8px;
border-radius: 0;
border-bottom: 2px solid transparent;
font-size: 13px;
font-weight: normal;
color: #999;
background: none;
}
.view-switcher-btn.active {
color: #333;
background: none;
border-bottom-color: #333;
}
.container {
padding: 4px 10px;
padding-top: calc(4px + env(safe-area-inset-top));
padding-bottom: 4px;
padding-left: 24px;
padding-right: 34px;
}
.header {
flex-direction: row;
align-items: center;
gap: 8px;
margin-bottom: 2px;
}
.month-navigator {
max-width: 55%;
width: auto;
flex-shrink: 1;
min-width: 0;
}
.month-btn {
padding: 2px 4px;
}
.month-preview {
width: 22px;
height: 22px;
}
.month-label {
font-size: 8px;
}
.nav-arrow {
width: 24px;
height: 24px;
font-size: 16px;
}
.content-wrapper {
flex-direction: row;
}
.chart-wrapper {
width: 55%;
height: calc(100dvh - 38px);
}
#details-box {
position: relative;
top: 0;
right: 0;
width: 45%;
min-width: auto;
margin-top: 0;
max-height: calc(100dvh - 38px);
overflow-y: auto;
padding: 10px;
}
.container.timeline-mode .chart-wrapper {
width: 100%;
height: calc(100dvh - 38px);
}
.details-header {
padding: 6px 0;
}
.top-item {
padding: 4px 0;
}
}
/* All landscape phones: compact center label, hide eye button */
@media (max-height: 500px) and (orientation: landscape) {
.center-label {
display: none;
}
.center-label.drilled-down {
display: flex;
align-items: center;
justify-content: center;
}
.center-label.drilled-down .center-home {
display: flex;
}
.center-label.drilled-down .center-month,
.center-label.drilled-down .center-category,
.center-label.drilled-down .center-amount {
display: none;
}
.chart-eye-btn {
display: none !important;
}
}
/* Larger landscape phones (e.g. iPhone Pro Max ~956×440): tighter details */
@media (min-width: 851px) and (max-height: 500px) and (orientation: landscape) {
h1 {
font-size: 24px;
white-space: nowrap;
}
.month-preview {
width: 28px;
height: 28px;
}
.container {
padding-left: 24px;
padding-right: 34px;
}
.chart-wrapper {
width: 49%;
height: calc(100dvh - 50px);
}
#details-box {
width: 40vw;
padding: 10px;
max-height: calc(100dvh - 50px);
right: 34px;
}
.details-header {
margin-bottom: 6px;
padding: 4px 0;
}
.hover-name {
font-size: 13px;
}
.hover-amount {
font-size: 16px;
}
#details-box h4 {
margin: 6px 0 2px;
font-size: 11px;
}
.top-item {
padding: 3px 0;
font-size: 12px;
}
.top-item-amount {
font-size: 12px;
}
}
/* Eye button for transaction details */
.eye-btn {
opacity: 0;
background: none;
border: none;
cursor: pointer;
padding: 2px 6px;
margin-left: 4px;
transition: opacity 0.2s;
flex-shrink: 0;
color: #666;
display: flex;
align-items: center;
}
.top-item:hover .eye-btn {
opacity: 0.5;
}
.eye-btn:hover {
opacity: 1 !important;
color: #333;
}
/* Header eye button - show on hover like other items */
.details-header:hover .header-eye-btn {
opacity: 0.5;
}
/* Always show eye buttons on touch/narrow devices (no hover) */
@media (max-width: 850px) {
.eye-btn,
.header-eye-btn {
opacity: 0.5;
}
}
@media (pointer: coarse) {
.eye-btn,
.header-eye-btn {
opacity: 0.5;
}
}
/* Floating eye button on chart (shown when hovering over sunburst sector) */
.chart-eye-btn {
position: absolute;
z-index: 100;
background: transparent;
border: none;
border-radius: 50%;
width: 24px;
height: 24px;
cursor: pointer !important;
display: flex;
align-items: center;
justify-content: center;
filter: drop-shadow(0 0 2px rgba(255, 255, 255, 1)) drop-shadow(0 0 3px rgba(255, 255, 255, 1)) drop-shadow(0 0 5px rgba(255, 255, 255, 0.9));
transition: filter 0.15s, opacity 0.2s ease-out;
color: #111;
pointer-events: none;
opacity: 0;
}
.chart-eye-btn:hover {
filter: drop-shadow(0 0 2px rgba(255, 255, 255, 1)) drop-shadow(0 0 4px rgba(255, 255, 255, 1)) drop-shadow(0 0 6px rgba(255, 255, 255, 1));
color: #000;
}
.chart-eye-btn svg {
width: 14px;
height: 14px;
}
/* Modal styles */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
width: 90vw;
max-width: 1200px;
height: 80vh;
background-color: white;
border-radius: 12px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
overflow: hidden;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
border-bottom: 1px solid #eee;
flex-shrink: 0;
}
.modal-header h2 {
margin: 0;
font-size: 18px;
color: #333;
}
.modal-close {
background: none;
border: none;
font-size: 28px;
cursor: pointer;
color: #666;
line-height: 1;
padding: 0 4px;
}
.modal-close:hover {
color: #333;
}
.modal-body {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.modal-table-container {
flex: 1;
overflow: scroll;
padding: 0;
}
.transaction-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
.transaction-table th,
.transaction-table td {
padding: 10px 12px;
text-align: left;
border-bottom: 1px solid #eee;
white-space: nowrap;
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
}
.transaction-table th {
background-color: #f8f9fa;
font-weight: 600;
color: #555;
position: sticky;
top: 0;
z-index: 1;
}
.transaction-table tbody tr:hover {
background-color: #f5f8ff;
}
.transaction-table tbody tr:last-child td {
border-bottom: none;
}
/* Mobile modal styles */
@media (max-width: 850px) {
.modal-content {
width: 95vw;
height: 90vh;
}
.transaction-table {
font-size: 11px;
}
.transaction-table th,
.transaction-table td {
padding: 8px 10px;
max-width: 150px;
}
}
/* Row detail modal styles */
.row-detail-content {
position: relative;
width: 90vw;
max-width: 500px;
max-height: 80vh;
background-color: white;
border-radius: 12px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
padding: 24px;
overflow-y: auto;
}
.row-detail-content .modal-close {
position: absolute;
top: 12px;
right: 12px;
}
.row-detail-content h3 {
margin: 0 0 20px 0;
font-size: 18px;
color: #333;
padding-right: 30px;
}
#row-detail-body {
display: table;
width: 100%;
border-collapse: collapse;
}
.row-detail-item {
display: table-row;
}
.row-detail-item:hover {
background-color: #f8f9fa;
}
.row-detail-label {
display: table-cell;
padding: 8px 32px 8px 0;
font-size: 13px;
color: #999;
font-weight: 400;
white-space: nowrap;
vertical-align: top;
border-bottom: 1px solid #eee;
min-width: 140px;
}
.row-detail-value {
display: table-cell;
padding: 8px 0;
font-size: 13px;
color: #222;
font-weight: 600;
word-break: break-word;
border-bottom: 1px solid #eee;
}
.row-detail-item:last-child .row-detail-label,
.row-detail-item:last-child .row-detail-value {
border-bottom: none;
}
/* Sortable table header styles */
.transaction-table th {
cursor: pointer;
user-select: none;
position: relative;
padding-right: 20px !important;
}
.transaction-table th:hover {
background-color: #f0f0f0;
}
.transaction-table th::after {
content: '';
position: absolute;
right: 6px;
top: 50%;
transform: translateY(-50%);
border: 4px solid transparent;
opacity: 0.3;
}
.transaction-table th.sort-asc::after {
border-bottom-color: #333;
border-top: none;
opacity: 1;
}
.transaction-table th.sort-desc::after {
border-top-color: #333;
border-bottom: none;
opacity: 1;
}
.transaction-table tbody tr {
cursor: pointer;
transition: background-color 0.15s;
}