openclacky 1.5.3 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.dockerignore +13 -0
  3. data/CHANGELOG.md +26 -0
  4. data/Dockerfile +21 -1
  5. data/README.md +26 -7
  6. data/README_CN.md +26 -7
  7. data/README_JA.md +26 -7
  8. data/lib/clacky/agent/message_compressor.rb +4 -29
  9. data/lib/clacky/agent/message_compressor_helper.rb +13 -15
  10. data/lib/clacky/agent/session_serializer.rb +6 -0
  11. data/lib/clacky/agent.rb +13 -1
  12. data/lib/clacky/agent_config.rb +6 -3
  13. data/lib/clacky/brand_config.rb +32 -12
  14. data/lib/clacky/default_extensions/ext-studio/agents/ext-developer/system_prompt.md +15 -0
  15. data/lib/clacky/default_extensions/ext-studio/api/handler.rb +1 -5
  16. data/lib/clacky/default_extensions/ext-studio/panels/studio/view.js +1 -1
  17. data/lib/clacky/default_extensions/ext-studio/skills/ext-develop/SKILL.md +5 -1
  18. data/lib/clacky/default_parsers/xlsx_parser.py +66 -0
  19. data/lib/clacky/extension/api_extension.rb +3 -2
  20. data/lib/clacky/message_format/open_ai.rb +26 -3
  21. data/lib/clacky/providers.rb +16 -8
  22. data/lib/clacky/server/http_server.rb +341 -24
  23. data/lib/clacky/server/project_manager.rb +150 -0
  24. data/lib/clacky/server/server_master.rb +7 -0
  25. data/lib/clacky/server/session_registry.rb +14 -1
  26. data/lib/clacky/session_manager.rb +5 -4
  27. data/lib/clacky/tools/file_reader.rb +2 -1
  28. data/lib/clacky/utils/model_pricing.rb +69 -18
  29. data/lib/clacky/utils/parser_manager.rb +115 -7
  30. data/lib/clacky/version.rb +1 -1
  31. data/lib/clacky/web/app.css +903 -135
  32. data/lib/clacky/web/app.js +11 -2
  33. data/lib/clacky/web/components/notify.js +139 -22
  34. data/lib/clacky/web/core/aside.js +21 -0
  35. data/lib/clacky/web/features/brand/store.js +3 -1
  36. data/lib/clacky/web/features/brand/view.js +29 -5
  37. data/lib/clacky/web/features/new-session/view.js +2 -2
  38. data/lib/clacky/web/features/trash/store.js +23 -9
  39. data/lib/clacky/web/features/trash/view.js +51 -0
  40. data/lib/clacky/web/i18n.js +95 -4
  41. data/lib/clacky/web/index.html +69 -15
  42. data/lib/clacky/web/projects.js +1143 -0
  43. data/lib/clacky/web/sessions.js +318 -537
  44. data/lib/clacky/web/settings.js +138 -5
  45. data/lib/clacky/web/ws-dispatcher.js +59 -1
  46. data/scripts/build/src/install_system_deps.sh.cc +11 -3
  47. data/scripts/install_system_deps.sh +11 -3
  48. metadata +5 -2
  49. data/lib/clacky/default_parsers/xlsx_parser.rb +0 -121
@@ -803,7 +803,7 @@ body {
803
803
  margin-bottom: 6px;
804
804
  border-bottom: 1px solid var(--color-border-secondary);
805
805
  }
806
- #ext-slot-sidebar-nav { padding: 6px 0 4px; }
806
+ #ext-slot-sidebar-nav { padding: 10px 0 0px; }
807
807
  #ext-slot-sidebar-nav-bottom {
808
808
  padding: 8px 0 10px;
809
809
  margin-top: 6px;
@@ -842,12 +842,46 @@ body {
842
842
  .sidebar-divider:has(.sidebar-divider-actions) {
843
843
  justify-content: space-between;
844
844
  }
845
+ /* Sessions divider: suppress the rule line (buttons fill the right side) */
846
+ .sidebar-divider--no-rule::after {
847
+ display: none;
848
+ }
845
849
  .sidebar-divider-actions {
846
850
  display: flex;
847
851
  align-items: center;
848
852
  gap: 4px;
849
853
  }
850
854
 
855
+ /* ── Chat section collapse ───────────────────────────────────────────────── */
856
+ #chat-section-header {
857
+ cursor: pointer;
858
+ z-index: 20;
859
+ }
860
+ .chat-section-title {
861
+ display: flex;
862
+ align-items: center;
863
+ gap: 3px;
864
+ white-space: nowrap;
865
+ flex: 0 0 auto;
866
+ }
867
+ .chat-section-chevron {
868
+ flex-shrink: 0;
869
+ color: var(--color-text-muted);
870
+ opacity: 0;
871
+ transition: transform 0.2s ease, opacity 0.15s ease;
872
+ margin-left: 1px;
873
+ }
874
+ #chat-section-header:hover .chat-section-chevron {
875
+ opacity: 1;
876
+ }
877
+ .chat-header-collapsed .chat-section-chevron {
878
+ opacity: 1;
879
+ transform: rotate(-90deg);
880
+ }
881
+ .chat-section-collapsed {
882
+ display: none;
883
+ }
884
+
851
885
  /* ── New Session button ──────────────────────────────────────────────────── */
852
886
  .btn-split-wrap {
853
887
  display: flex;
@@ -1503,21 +1537,29 @@ body {
1503
1537
  /* Actions button (⋯) on session list items — visible only on hover */
1504
1538
  .session-actions-btn {
1505
1539
  flex-shrink: 0;
1506
- display: none;
1540
+ display: flex;
1507
1541
  align-items: center;
1508
1542
  justify-content: center;
1509
- width: 1.5rem;
1543
+ width: 0;
1510
1544
  height: 1.5rem;
1545
+ overflow: hidden;
1511
1546
  background: transparent;
1512
1547
  border: none;
1513
1548
  border-radius: 4px;
1514
1549
  color: var(--color-text-muted);
1515
1550
  cursor: pointer;
1516
1551
  padding: 0;
1517
- transition: background .15s, color .15s;
1552
+ opacity: 0;
1553
+ pointer-events: none;
1554
+ transition: background .15s, color .15s, width .15s, opacity .15s;
1518
1555
  align-self: center;
1519
1556
  }
1520
- .session-item:hover .session-actions-btn { display: flex; }
1557
+ .session-item:hover .session-actions-btn,
1558
+ .session-item.active .session-actions-btn {
1559
+ width: 1.5rem;
1560
+ opacity: 1;
1561
+ pointer-events: auto;
1562
+ }
1521
1563
  .session-actions-btn:hover {
1522
1564
  background: var(--color-border-primary);
1523
1565
  color: var(--color-text-primary);
@@ -2175,9 +2217,6 @@ body {
2175
2217
  }
2176
2218
 
2177
2219
  /* ── Starter Prompts ── */
2178
- .new-session-starter-prompts {
2179
- margin-top: 0.25rem;
2180
- }
2181
2220
  .ns-starter-label {
2182
2221
  font-size: 0.75rem;
2183
2222
  color: var(--color-text-tertiary);
@@ -2580,19 +2619,20 @@ body {
2580
2619
 
2581
2620
  .session-aside-collapse {
2582
2621
  position: absolute;
2583
- top: 7px;
2584
- right: 8px;
2622
+ top: 4px;
2623
+ right: 0.5rem;
2585
2624
  z-index: 11;
2586
2625
  display: inline-flex;
2587
2626
  align-items: center;
2588
2627
  justify-content: center;
2589
- width: 1.625rem;
2590
- height: 1.625rem;
2591
- border: none;
2592
- background: transparent;
2593
- color: var(--color-text-tertiary);
2628
+ width: 2rem;
2629
+ height: 2rem;
2630
+ border: 1px solid var(--color-border-primary);
2631
+ background: var(--color-bg-secondary);
2632
+ color: var(--color-text-secondary);
2594
2633
  border-radius: var(--radius-sm);
2595
2634
  cursor: pointer;
2635
+ box-shadow: var(--shadow-sm, 0 2px 8px rgba(0,0,0,0.06));
2596
2636
  transition: background-color var(--transition-base), color var(--transition-base);
2597
2637
  }
2598
2638
  .session-aside-collapse:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
@@ -3405,6 +3445,32 @@ body {
3405
3445
  color: var(--color-text-secondary);
3406
3446
  }
3407
3447
  .msg-success { color: var(--color-success); align-self: flex-start; font-size: 0.8125rem; }
3448
+
3449
+ /* ── Ext-developer reload hint ─────────────────────────────────────────────── */
3450
+ .msg-ext-refresh-hint {
3451
+ align-self: flex-start;
3452
+ margin: 0 -1rem;
3453
+ }
3454
+ .btn-ext-refresh {
3455
+ display: inline-flex;
3456
+ align-items: center;
3457
+ gap: 0.4rem;
3458
+ padding: 0.375rem 0.75rem;
3459
+ font-size: 0.8125rem;
3460
+ font-weight: 500;
3461
+ color: var(--color-accent-primary);
3462
+ background: transparent;
3463
+ border: 1px solid var(--color-accent-primary);
3464
+ border-radius: 0.375rem;
3465
+ cursor: pointer;
3466
+ transition: background 0.15s, opacity 0.15s;
3467
+ }
3468
+ .btn-ext-refresh:hover:not(:disabled) {
3469
+ background: color-mix(in srgb, var(--color-accent-primary) 10%, transparent);
3470
+ }
3471
+ .btn-ext-refresh:disabled {
3472
+ cursor: default;
3473
+ }
3408
3474
  .tool-name { color: var(--color-warning); font-weight: 600; }
3409
3475
  .progress-msg { color: var(--color-accent-primary); font-size: 0.75rem; align-self: center; }
3410
3476
 
@@ -5884,181 +5950,226 @@ body {
5884
5950
  padding: 1rem 1.25rem;
5885
5951
  border-top: 1px solid var(--color-border-primary);
5886
5952
  }
5887
- .dir-picker-input {
5888
- width: 100%;
5889
- padding: 0.5rem 0.75rem;
5890
- border: 1px solid var(--color-border-primary);
5891
- border-radius: 6px;
5953
+ /* ── Dir Picker — Finder-style ────────────────────────────────────── */
5954
+ .dp-modal {
5955
+ max-width: 680px;
5956
+ width: 680px;
5957
+ max-height: 85vh;
5958
+ display: flex;
5959
+ flex-direction: column;
5960
+ padding: 0;
5961
+ overflow: hidden;
5962
+ border-radius: 10px;
5963
+ }
5964
+
5965
+ /* Toolbar */
5966
+ .dp-toolbar {
5967
+ display: flex;
5968
+ align-items: center;
5969
+ gap: 0.5rem;
5970
+ padding: 0.625rem 1rem;
5971
+ border-bottom: 1px solid var(--color-border-primary);
5972
+ background: var(--color-bg-secondary);
5973
+ flex-shrink: 0;
5974
+ }
5975
+ .dp-nav-btns {
5976
+ display: flex;
5977
+ gap: 2px;
5978
+ }
5979
+ .dp-nav-btn {
5980
+ display: inline-flex;
5981
+ align-items: center;
5982
+ justify-content: center;
5983
+ width: 26px;
5984
+ height: 26px;
5985
+ padding: 0;
5986
+ border: 1px solid rgba(0,0,0,0.18);
5987
+ border-radius: 5px;
5892
5988
  background: var(--color-bg-primary);
5893
5989
  color: var(--color-text-primary);
5894
- font-size: 0.875rem;
5895
- font-family: var(--font-mono, monospace);
5896
- transition: border-color 0.15s;
5897
- box-sizing: border-box;
5898
- }.dir-picker-input:focus {
5899
- outline: none;
5900
- border-color: var(--color-accent);
5990
+ cursor: pointer;
5991
+ transition: background 0.1s;
5901
5992
  }
5902
- .dir-picker-input::placeholder {
5903
- color: var(--color-text-tertiary);
5993
+ .dp-nav-btn:hover:not(:disabled) {
5994
+ background: var(--color-bg-hover);
5904
5995
  }
5905
- .dp-hidden-toggle {
5996
+ .dp-nav-btn:disabled {
5997
+ opacity: 0.3;
5998
+ cursor: not-allowed;
5999
+ }
6000
+ /* Breadcrumb */
6001
+ .dp-breadcrumb {
5906
6002
  display: flex;
5907
6003
  align-items: center;
5908
- gap: 0.375rem;
6004
+ gap: 0;
6005
+ flex: 1;
6006
+ min-width: 0;
6007
+ overflow-x: auto;
6008
+ overflow-y: hidden;
6009
+ scrollbar-width: none; /* Firefox */
6010
+ -ms-overflow-style: none; /* IE */
6011
+ /* Left fade mask when content overflows */
6012
+ -webkit-mask-image: linear-gradient(to right, transparent 0px, black 32px);
6013
+ mask-image: linear-gradient(to right, transparent 0px, black 32px);
6014
+ }
6015
+ .dp-breadcrumb::-webkit-scrollbar {
6016
+ display: none;
6017
+ }
6018
+ .dp-bc-seg {
5909
6019
  font-size: 0.8125rem;
5910
6020
  color: var(--color-text-secondary);
5911
6021
  cursor: pointer;
5912
- user-select: none;
6022
+ white-space: nowrap;
6023
+ padding: 3px 6px;
6024
+ border-radius: 4px;
6025
+ transition: background 0.1s, color 0.1s;
5913
6026
  }
5914
- .dp-hidden-toggle input {
5915
- cursor: pointer;
5916
- margin: 0;
6027
+ .dp-bc-seg:hover {
6028
+ background: rgba(0,0,0,0.07);
6029
+ color: var(--color-text-primary);
5917
6030
  }
5918
- /* Preset buttons row */
5919
- .dp-presets {
5920
- display: flex;
5921
- gap: 0.5rem;
5922
- flex-wrap: wrap;
6031
+ .dp-bc-current {
6032
+ color: var(--color-text-primary);
6033
+ font-weight: 500;
6034
+ cursor: default;
5923
6035
  }
5924
- .dp-presets .btn-sm {
5925
- padding: 0.25rem 0.625rem;
5926
- font-size: 0.75rem;
6036
+ .dp-bc-current:hover {
6037
+ background: transparent;
5927
6038
  }
5928
- .dp-up-btn {
6039
+ .dp-bc-sep {
5929
6040
  display: inline-flex;
5930
6041
  align-items: center;
5931
- gap: 0.25rem;
5932
- }
5933
- .dp-up-btn svg { flex-shrink: 0; }
5934
- .dp-up-btn:disabled {
5935
- opacity: 0.45;
5936
- cursor: not-allowed;
6042
+ color: var(--color-text-tertiary);
6043
+ flex-shrink: 0;
5937
6044
  }
5938
- /* Path input container */
5939
- .dp-path-container {
6045
+ .dp-bc-folder-icon {
6046
+ display: inline-flex;
6047
+ align-items: center;
6048
+ color: var(--color-text-secondary);
6049
+ margin-right: 3px;
5940
6050
  flex-shrink: 0;
5941
- position: relative;
5942
- }/* Autocomplete dropdown */
5943
- .dp-autocomplete {
5944
- position: absolute;
5945
- top: 100%;
5946
- left: 0;
5947
- right: 0;
5948
- z-index: 10;
5949
- max-height: 200px;
5950
- overflow-y: auto;
5951
- background: var(--color-bg-primary);
5952
- border: 1px solid var(--color-border-primary);
5953
- border-top: none;
5954
- border-radius: 0 0 6px 6px;
5955
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
5956
6051
  }
5957
- .dp-ac-item {
6052
+
6053
+ /* Column header */
6054
+ .dp-col-header {
5958
6055
  display: flex;
5959
6056
  align-items: center;
5960
- gap: 0.5rem;
5961
- padding: 0.4rem 0.75rem;
5962
- cursor: pointer;
5963
- font-size: 0.8125rem;
5964
- color: var(--color-text-primary);
5965
- transition: background 0.1s;
6057
+ padding: 0.3rem 1rem;
6058
+ border-bottom: 1px solid var(--color-border-primary);
6059
+ background: var(--color-bg-secondary);
6060
+ flex-shrink: 0;
5966
6061
  }
5967
- .dp-ac-item:hover,
5968
- .dp-ac-item.active {
5969
- background: var(--color-bg-hover);
6062
+ .dp-col-name {
6063
+ flex: 1;
6064
+ font-size: 0.75rem;
6065
+ font-weight: 600;
6066
+ color: var(--color-text-tertiary);
6067
+ text-transform: uppercase;
6068
+ letter-spacing: 0.04em;
5970
6069
  }
5971
- .dp-ac-icon {
5972
- display: inline-flex;
6070
+
6071
+ /* Hidden-files toggle (in header) */
6072
+ .dp-hidden-toggle {
6073
+ display: flex;
5973
6074
  align-items: center;
5974
- flex-shrink: 0;
5975
- color: var(--color-text-secondary);
6075
+ gap: 0.375rem;
6076
+ font-size: 0.75rem;
6077
+ color: var(--color-text-tertiary);
6078
+ cursor: pointer;
6079
+ user-select: none;
5976
6080
  }
5977
- .dp-ac-name {
5978
- overflow: hidden;
5979
- text-overflow: ellipsis;
5980
- white-space: nowrap;
6081
+ .dp-hidden-toggle input {
6082
+ cursor: pointer;
6083
+ margin: 0;
5981
6084
  }
5982
- /* Tree container */
5983
- .dp-tree {
5984
- border: 1px solid var(--color-border-primary);
5985
- border-radius: 6px;
5986
- background: var(--color-bg-secondary);
5987
- min-height: 200px;
5988
- max-height: 340px;
5989
- overflow: auto;
5990
- font-size: 0.8125rem;
6085
+
6086
+ /* List area */
6087
+ .dp-list {
6088
+ flex: 1;
6089
+ overflow-y: auto;
6090
+ min-height: 320px;
6091
+ padding-top: 0.35rem;
6092
+ background: var(--color-bg-primary);
5991
6093
  }
5992
- /* Tree node */
5993
6094
  .dp-node {
5994
6095
  user-select: none;
5995
6096
  }
5996
6097
  .dp-row {
5997
6098
  display: flex;
5998
6099
  align-items: center;
5999
- gap: 0.375rem;
6000
- padding: 0.375rem 0.5rem;
6100
+ gap: 0.5rem;
6101
+ padding: 0.4rem 0.75rem;
6102
+ margin: 0 0.5rem;
6103
+ border-radius: 6px;
6001
6104
  cursor: pointer;
6002
- border-radius: 4px;
6003
- transition: background 0.1s;
6105
+ transition: background 0.08s;
6004
6106
  }
6005
6107
  .dp-row:hover {
6006
6108
  background: var(--color-bg-hover);
6007
6109
  }
6008
6110
  .dp-row.selected {
6009
- background: var(--color-accent-subtle, rgba(59, 130, 246, 0.12));
6111
+ background: var(--color-accent, #3b82f6);
6010
6112
  }
6011
6113
  .dp-row.selected .dp-name {
6012
- color: var(--color-accent);
6114
+ color: #fff;
6013
6115
  font-weight: 500;
6014
6116
  }
6015
- /* Caret */
6016
- .dp-caret {
6017
- display: inline-flex;
6018
- align-items: center;
6019
- justify-content: center;
6020
- width: 16px;
6021
- height: 16px;
6022
- flex-shrink: 0;
6023
- color: var(--color-text-tertiary);
6024
- transition: transform 0.15s;
6025
- }
6026
- .dp-caret.open {
6027
- transform: rotate(90deg);
6117
+ .dp-row.selected .dp-icon {
6118
+ color: rgba(255,255,255,0.85);
6028
6119
  }
6029
- /* Folder icon */
6030
6120
  .dp-icon {
6031
6121
  display: inline-flex;
6032
6122
  align-items: center;
6033
6123
  flex-shrink: 0;
6034
6124
  color: var(--color-text-secondary);
6035
6125
  }
6036
- .dp-row.selected .dp-icon {
6037
- color: var(--color-accent);
6038
- }
6039
- /* Name */
6040
6126
  .dp-name {
6041
6127
  flex: 1;
6042
6128
  overflow: hidden;
6043
6129
  text-overflow: ellipsis;
6044
6130
  white-space: nowrap;
6045
6131
  color: var(--color-text-primary);
6132
+ font-size: 0.875rem;
6133
+ }
6134
+ .dp-name-input {
6135
+ flex: 1;
6136
+ border: 1px solid var(--color-accent, #3b82f6);
6137
+ border-radius: 4px;
6138
+ padding: 1px 4px;
6139
+ font-size: 0.875rem;
6140
+ background: var(--color-bg-primary);
6141
+ color: var(--color-text-primary);
6142
+ outline: none;
6046
6143
  }
6047
- /* Children container */
6048
- .dp-children {
6049
- display: flex;
6050
- flex-direction: column;
6051
- }/* Loading / empty / error states */
6052
6144
  .dp-loading,
6053
6145
  .dp-empty,
6054
6146
  .dp-error {
6055
- padding: 0.5rem 1rem;
6147
+ padding: 2rem 1rem;
6148
+ text-align: center;
6056
6149
  color: var(--color-text-tertiary);
6057
- font-size: 0.75rem;
6058
- font-style: italic;
6150
+ font-size: 0.8125rem;
6059
6151
  }
6060
- .dp-error {
6061
- color: var(--color-text-danger, #ef4444);
6152
+ .dp-error { color: var(--color-text-danger, #ef4444); }
6153
+
6154
+ /* Footer */
6155
+ .dp-footer {
6156
+ display: flex;
6157
+ align-items: center;
6158
+ justify-content: space-between;
6159
+ padding: 0.75rem 1rem;
6160
+ border-top: 1px solid var(--color-border-primary);
6161
+ background: var(--color-bg-secondary);
6162
+ flex-shrink: 0;
6163
+ }
6164
+ .dp-footer-actions {
6165
+ display: flex;
6166
+ gap: 0.5rem;
6167
+ }
6168
+ .dp-newfolder-btn {
6169
+ display: inline-flex;
6170
+ align-items: center;
6171
+ gap: 0.25rem;
6172
+ font-size: 0.8125rem;
6062
6173
  }
6063
6174
  /* Model name combobox */
6064
6175
  .model-name-combobox {
@@ -7456,7 +7567,7 @@ body {
7456
7567
  }
7457
7568
  .extensions-filter-tab-active {
7458
7569
  color: var(--color-text-primary);
7459
- border-bottom-color: var(--color-accent, #6366f1);
7570
+ border-bottom-color: var(--color-accent-primary);
7460
7571
  }
7461
7572
  .extensions-search {
7462
7573
  flex: 1;
@@ -9101,17 +9212,53 @@ body.setup-mode[data-theme="dark"] {
9101
9212
  }
9102
9213
 
9103
9214
  /* ── Brand & License settings section ───────────────────────────────────── */
9104
- .brand-status-card {
9215
+ .platform-source-card {
9105
9216
  background: var(--color-bg-secondary);
9106
9217
  border: 1px solid var(--color-border-primary);
9107
9218
  border-radius: 10px;
9108
9219
  padding: 1rem 1.25rem;
9109
9220
  display: flex;
9110
9221
  flex-direction: column;
9111
- gap: 0.625rem;
9222
+ gap: 0.75rem;
9112
9223
  }
9113
- /* Inner layout: status fields on the left, QR code on the right */
9114
- .brand-status-main {
9224
+ .platform-source-desc {
9225
+ font-size: 0.8125rem;
9226
+ color: var(--color-text-secondary);
9227
+ line-height: 1.5;
9228
+ margin: 0;
9229
+ }
9230
+ .platform-source-field {
9231
+ display: flex;
9232
+ flex-direction: column;
9233
+ gap: 0.375rem;
9234
+ }
9235
+ .platform-source-label {
9236
+ font-size: 0.75rem;
9237
+ color: var(--color-text-secondary);
9238
+ }
9239
+ .platform-source-row {
9240
+ display: flex;
9241
+ align-items: center;
9242
+ gap: 0.5rem;
9243
+ flex-wrap: wrap;
9244
+ }
9245
+ .platform-source-row .field-input {
9246
+ flex: 1;
9247
+ min-width: 12rem;
9248
+ font-family: var(--font-mono, monospace);
9249
+ }
9250
+
9251
+ .brand-status-card {
9252
+ background: var(--color-bg-secondary);
9253
+ border: 1px solid var(--color-border-primary);
9254
+ border-radius: 10px;
9255
+ padding: 1rem 1.25rem;
9256
+ display: flex;
9257
+ flex-direction: column;
9258
+ gap: 0.625rem;
9259
+ }
9260
+ /* Inner layout: status fields on the left, QR code on the right */
9261
+ .brand-status-main {
9115
9262
  display: flex;
9116
9263
  align-items: flex-start;
9117
9264
  gap: 1.25rem;
@@ -10742,6 +10889,28 @@ body.setup-mode[data-theme="dark"] {
10742
10889
  font-size: 0.6875rem;
10743
10890
  color: var(--color-text-muted);
10744
10891
  }
10892
+ .trash-session-project-badge {
10893
+ display: inline-flex;
10894
+ align-items: center;
10895
+ gap: 0.25rem;
10896
+ padding: 0.125rem 0.4rem;
10897
+ border-radius: 4px;
10898
+ background: var(--color-bg-tertiary, var(--color-bg-primary));
10899
+ border: 1px solid var(--color-border-primary);
10900
+ color: var(--color-text-secondary);
10901
+ font-size: 0.625rem;
10902
+ white-space: nowrap;
10903
+ max-width: 8rem;
10904
+ overflow: hidden;
10905
+ text-overflow: ellipsis;
10906
+ }
10907
+ .trash-session-project-dot {
10908
+ width: 6px;
10909
+ height: 6px;
10910
+ border-radius: 50%;
10911
+ background: var(--color-text-muted);
10912
+ flex-shrink: 0;
10913
+ }
10745
10914
  .trash-session-card-actions {
10746
10915
  display: flex;
10747
10916
  align-items: center;
@@ -10839,6 +11008,38 @@ body.setup-mode[data-theme="dark"] {
10839
11008
  border-color: var(--color-accent-primary);
10840
11009
  color: #fff;
10841
11010
  }
11011
+ /* Project filter dropdown */
11012
+ .trash-filter-project-wrap {
11013
+ display: inline-flex;
11014
+ align-items: center;
11015
+ gap: 0.3rem;
11016
+ padding: 0.2rem 0.45rem 0.2rem 0.55rem;
11017
+ border-radius: 5px;
11018
+ border: 1px solid var(--color-border-primary);
11019
+ background: transparent;
11020
+ color: var(--color-text-muted);
11021
+ cursor: pointer;
11022
+ transition: border-color 0.14s, color 0.14s;
11023
+ }
11024
+ .trash-filter-project-wrap:focus-within {
11025
+ border-color: var(--color-accent-primary);
11026
+ color: var(--color-text-primary);
11027
+ }
11028
+ .trash-filter-project-icon {
11029
+ flex-shrink: 0;
11030
+ pointer-events: none;
11031
+ }
11032
+ .trash-filter-project-select {
11033
+ font-size: 0.6875rem;
11034
+ color: inherit;
11035
+ background: transparent;
11036
+ border: none;
11037
+ outline: none;
11038
+ cursor: pointer;
11039
+ padding: 0;
11040
+ max-width: 130px;
11041
+ appearance: auto;
11042
+ }
10842
11043
  .trash-actions {
10843
11044
  display: flex;
10844
11045
  align-items: center;
@@ -13000,7 +13201,7 @@ body.setup-mode[data-theme="dark"] {
13000
13201
  margin-left: 0 !important;
13001
13202
  }
13002
13203
  /* active session: always show ⋯ button (no hover on touch) */
13003
- .session-item.active .session-actions-btn { display: flex; }
13204
+ .session-item.active .session-actions-btn { width: 1.5rem; opacity: 1; pointer-events: auto; }
13004
13205
  #sidebar.hidden {
13005
13206
  transform: translateX(-100%);
13006
13207
  margin-left: 0 !important;
@@ -13496,3 +13697,570 @@ body.setup-mode[data-theme="dark"] {
13496
13697
  background: var(--color-bg-primary);
13497
13698
  }
13498
13699
  }
13700
+
13701
+ /* ══════════════════════════════════════════════════════════════════════════════
13702
+ Projects sidebar section
13703
+ ══════════════════════════════════════════════════════════════════════════════ */
13704
+
13705
+ /* ── Empty hint ────────────────────────────────────────────────────────────── */
13706
+ .project-empty-hint {
13707
+ padding: 0.375rem 0.75rem;
13708
+ font-size: 0.75rem;
13709
+ color: var(--color-text-muted);
13710
+ }
13711
+
13712
+ /* ── Section-level collapse ────────────────────────────────────────────────── */
13713
+ .projects-section-title {
13714
+ display: inline-flex;
13715
+ align-items: center;
13716
+ gap: 3px;
13717
+ cursor: pointer;
13718
+ }
13719
+ .projects-section-chevron {
13720
+ flex-shrink: 0;
13721
+ color: var(--color-text-muted);
13722
+ opacity: 0;
13723
+ transition: transform 0.2s ease, opacity 0.15s ease;
13724
+ margin-left: 1px;
13725
+ }
13726
+ #projects-section-header:hover .projects-section-chevron {
13727
+ opacity: 1;
13728
+ }
13729
+ .projects-section-collapsed .projects-section-chevron {
13730
+ opacity: 1;
13731
+ transform: rotate(-90deg);
13732
+ }
13733
+ .project-list-collapsed {
13734
+ display: none;
13735
+ }
13736
+
13737
+ /* ── Project group header row ──────────────────────────────────────────────── */
13738
+ .project-group-header {
13739
+ display: flex;
13740
+ align-items: center;
13741
+ gap: 0.375rem;
13742
+ padding: 0.3125rem 0.625rem;
13743
+ border-radius: var(--radius-sm);
13744
+ cursor: pointer;
13745
+ user-select: none;
13746
+ transition: background var(--transition-fast);
13747
+ }
13748
+ .project-group-header:hover {
13749
+ background: var(--color-bg-hover);
13750
+ }
13751
+
13752
+ .project-name {
13753
+ flex: 1;
13754
+ min-width: 0;
13755
+ overflow: hidden;
13756
+ text-overflow: ellipsis;
13757
+ white-space: nowrap;
13758
+ font-size: 0.8125rem;
13759
+ color: var(--color-text-primary);
13760
+ }
13761
+
13762
+ /* Actions button (⋯) — shown only on hover */
13763
+ .project-actions-btn {
13764
+ flex-shrink: 0;
13765
+ display: flex;
13766
+ align-items: center;
13767
+ justify-content: center;
13768
+ width: 0;
13769
+ height: 1.375rem;
13770
+ overflow: hidden;
13771
+ background: transparent;
13772
+ border: none;
13773
+ border-radius: 4px;
13774
+ color: var(--color-text-secondary);
13775
+ cursor: pointer;
13776
+ padding: 0;
13777
+ opacity: 0;
13778
+ pointer-events: none;
13779
+ transition: background var(--transition-fast), color var(--transition-fast), opacity var(--transition-fast), width var(--transition-fast);
13780
+ }
13781
+ .project-group-header:hover .project-actions-btn {
13782
+ width: 1.375rem;
13783
+ opacity: 1;
13784
+ pointer-events: auto;
13785
+ }
13786
+ .project-actions-btn:hover {
13787
+ background: var(--color-border-primary);
13788
+ color: var(--color-text-primary);
13789
+ }
13790
+
13791
+ /* ── Session group (indented children) ────────────────────────────────────── */
13792
+ .project-session-group {
13793
+ padding-left: 0.875rem;
13794
+ margin-top: 0.08rem;
13795
+ }
13796
+
13797
+ .project-sessions-empty {
13798
+ padding: 0.25rem 0.5rem 0.25rem 0.625rem;
13799
+ font-size: 0.75rem;
13800
+ color: var(--color-text-muted);
13801
+ }
13802
+
13803
+ /* ── Project hover tooltip ─────────────────────────────────────────────────── */
13804
+ .project-tooltip {
13805
+ position: fixed;
13806
+ z-index: 1200;
13807
+ background: var(--color-bg-secondary);
13808
+ border: 1px solid var(--color-border-primary);
13809
+ border-radius: 10px;
13810
+ box-shadow: 0 8px 24px rgba(0,0,0,.10), 0 2px 8px rgba(0,0,0,.06);
13811
+ padding: 0.75rem 0.875rem 0.75rem 1.125rem; /* extra left padding = visual gap */
13812
+ min-width: 13rem;
13813
+ max-width: 18rem;
13814
+ animation: fadeIn 0.12s ease;
13815
+ }
13816
+ /* Transparent bridge on the left side fills the gap between sidebar and tooltip */
13817
+ .project-tooltip::before {
13818
+ content: "";
13819
+ position: absolute;
13820
+ top: 0;
13821
+ left: -8px;
13822
+ width: 8px;
13823
+ height: 100%;
13824
+ }
13825
+ [data-theme="dark"] .project-tooltip {
13826
+ box-shadow: 0 8px 28px rgba(0,0,0,.55), 0 2px 8px rgba(0,0,0,.35);
13827
+ }
13828
+
13829
+ .project-tooltip-header {
13830
+ display: flex;
13831
+ align-items: center;
13832
+ gap: 0.4rem;
13833
+ margin-bottom: 0.75rem;
13834
+ }
13835
+ .project-tooltip-icon {
13836
+ flex-shrink: 0;
13837
+ display: flex;
13838
+ align-items: center;
13839
+ justify-content: center;
13840
+ color: var(--color-text-secondary);
13841
+ line-height: 0;
13842
+ }
13843
+ .project-tooltip-icon svg {
13844
+ display: block;
13845
+ flex-shrink: 0;
13846
+ }
13847
+ .project-tooltip-name {
13848
+ flex: 1;
13849
+ min-width: 0;
13850
+ font-size: 0.8125rem;
13851
+ font-weight: 600;
13852
+ color: var(--color-text-primary);
13853
+ overflow: hidden;
13854
+ text-overflow: ellipsis;
13855
+ white-space: nowrap;
13856
+ }
13857
+ .project-tooltip-rows {
13858
+ display: flex;
13859
+ flex-direction: column;
13860
+ gap: 0.3rem;
13861
+ }
13862
+ .project-tooltip-row {
13863
+ display: flex;
13864
+ align-items: center;
13865
+ gap: 0.4rem;
13866
+ font-size: 0.75rem;
13867
+ color: var(--color-text-secondary);
13868
+ min-width: 0;
13869
+ }
13870
+ .project-tooltip-row--clickable {
13871
+ cursor: pointer;
13872
+ border-radius: 4px;
13873
+ margin: 0 -0.25rem;
13874
+ padding: 0.15rem 0.25rem;
13875
+ transition: background var(--transition-fast);
13876
+ }
13877
+ .project-tooltip-row--clickable:hover {
13878
+ background: var(--color-bg-hover);
13879
+ }
13880
+
13881
+ .project-tooltip-divider {
13882
+ height: 1px;
13883
+ background: var(--color-border-primary);
13884
+ margin: 0.25rem 0;
13885
+ }
13886
+
13887
+ .project-tooltip-row-icon {
13888
+ flex-shrink: 0;
13889
+ color: var(--color-text-muted);
13890
+ display: flex;
13891
+ align-items: center;
13892
+ line-height: 0;
13893
+ }
13894
+ .project-tooltip-row-icon svg {
13895
+ display: block;
13896
+ flex-shrink: 0;
13897
+ }
13898
+ .project-tooltip-row-text {
13899
+ min-width: 0;
13900
+ overflow: hidden;
13901
+ text-overflow: ellipsis;
13902
+ white-space: nowrap;
13903
+ line-height: 1.4;
13904
+ }
13905
+
13906
+ /* ── Project context menu (rename / delete) ────────────────────────────────── */
13907
+ .project-actions-menu {
13908
+ background: var(--color-bg-secondary);
13909
+ border: 1px solid var(--color-border-primary);
13910
+ border-radius: 8px;
13911
+ box-shadow: 0 6px 20px rgba(0,0,0,.08), 0 2px 6px rgba(0,0,0,.04);
13912
+ padding: 0.25rem;
13913
+ min-width: 9rem;
13914
+ z-index: 1000;
13915
+ animation: fadeIn 0.15s ease;
13916
+ }
13917
+ [data-theme="dark"] .project-actions-menu {
13918
+ box-shadow: 0 8px 24px rgba(0,0,0,.5), 0 2px 6px rgba(0,0,0,.3);
13919
+ }
13920
+ .project-actions-menu-item {
13921
+ display: block;
13922
+ width: 100%;
13923
+ padding: 0.375rem 0.625rem;
13924
+ border: none;
13925
+ background: transparent;
13926
+ border-radius: 5px;
13927
+ cursor: pointer;
13928
+ color: var(--color-text-primary);
13929
+ font-size: 0.8125rem;
13930
+ text-align: left;
13931
+ transition: background .12s ease, color .12s ease;
13932
+ }
13933
+ .project-actions-menu-item:hover {
13934
+ background: var(--color-bg-hover);
13935
+ }
13936
+ .project-actions-menu-item.danger {
13937
+ color: var(--color-error);
13938
+ margin-top: 0.25rem;
13939
+ position: relative;
13940
+ }
13941
+ .project-actions-menu-item.danger::before {
13942
+ content: "";
13943
+ position: absolute;
13944
+ left: 0;
13945
+ right: 0;
13946
+ top: -0.1875rem;
13947
+ height: 1px;
13948
+ background: var(--color-border-secondary);
13949
+ }
13950
+ .project-actions-menu-item.danger:hover {
13951
+ background: var(--color-error-bg);
13952
+ }
13953
+
13954
+ /* ── Organize menu (view-mode toggle) ──────────────────────────────────────── */
13955
+ .project-organize-menu {
13956
+ background: var(--color-bg-secondary);
13957
+ border: 1px solid var(--color-border-primary);
13958
+ border-radius: 8px;
13959
+ box-shadow: 0 6px 20px rgba(0,0,0,.08), 0 2px 6px rgba(0,0,0,.04);
13960
+ padding: 0.25rem;
13961
+ min-width: 10rem;
13962
+ z-index: 1000;
13963
+ animation: fadeIn 0.15s ease;
13964
+ }
13965
+ [data-theme="dark"] .project-organize-menu {
13966
+ box-shadow: 0 8px 24px rgba(0,0,0,.5), 0 2px 6px rgba(0,0,0,.3);
13967
+ }
13968
+ .project-organize-divider {
13969
+ height: 1px;
13970
+ background: var(--color-border-primary);
13971
+ margin: 0.25rem 0.375rem;
13972
+ }
13973
+ .project-organize-section-label {
13974
+ padding: 0.25rem 0.625rem 0.125rem;
13975
+ font-size: 0.6875rem;
13976
+ color: var(--color-text-secondary);
13977
+ font-weight: 500;
13978
+ letter-spacing: 0.01em;
13979
+ }
13980
+ .project-organize-item {
13981
+ display: block;
13982
+ width: 100%;
13983
+ padding: 0.375rem 0.625rem;
13984
+ border: none;
13985
+ background: transparent;
13986
+ border-radius: 5px;
13987
+ cursor: pointer;
13988
+ color: var(--color-text-primary);
13989
+ font-size: 0.8125rem;
13990
+ text-align: left;
13991
+ transition: background .12s ease, color .12s ease;
13992
+ }
13993
+ .project-organize-item:hover {
13994
+ background: var(--color-bg-hover);
13995
+ }
13996
+ .project-organize-item.active {
13997
+ color: var(--color-accent-primary);
13998
+ font-weight: 500;
13999
+ }
14000
+
14001
+ /* ── Flat mode ─────────────────────────────────────────────────────────────── */
14002
+ .project-session-tag {
14003
+ padding: 0 0.625rem 0.1rem;
14004
+ font-size: 0.6875rem;
14005
+ font-weight: 500;
14006
+ color: var(--project-color, var(--color-accent-primary));
14007
+ opacity: 0.85;
14008
+ white-space: nowrap;
14009
+ overflow: hidden;
14010
+ text-overflow: ellipsis;
14011
+ }
14012
+
14013
+ /* ── Project icon badge (sidebar header) ─────────────────────────────────── */
14014
+ .project-icon-badge {
14015
+ display: inline-flex;
14016
+ align-items: center;
14017
+ justify-content: center;
14018
+ flex-shrink: 0;
14019
+ width: 1rem;
14020
+ height: 1rem;
14021
+ }
14022
+ .project-icon-badge svg {
14023
+ display: block;
14024
+ }
14025
+
14026
+ /* ── Create-project modal: input row (trigger + name input) ──────────────── */
14027
+ .create-project-input-row {
14028
+ display: flex;
14029
+ align-items: center;
14030
+ gap: 0.5rem;
14031
+ }
14032
+
14033
+ /* Trigger button (icon preview) */
14034
+ .project-icon-trigger {
14035
+ flex-shrink: 0;
14036
+ display: inline-flex;
14037
+ align-items: center;
14038
+ justify-content: center;
14039
+ width: 2.25rem;
14040
+ height: 2.25rem;
14041
+ border-radius: 6px;
14042
+ border: 1px solid var(--color-border-primary);
14043
+ background: transparent;
14044
+ color: var(--color-text-primary);
14045
+ cursor: pointer;
14046
+ padding: 0;
14047
+ transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.1s;
14048
+ }
14049
+ .project-icon-trigger:hover {
14050
+ background: var(--color-bg-hover);
14051
+ border-color: var(--color-border-secondary);
14052
+ }
14053
+ .project-icon-trigger svg {
14054
+ display: block;
14055
+ pointer-events: none;
14056
+ }
14057
+
14058
+ /* Name input fills remaining space */
14059
+ .create-project-name-input {
14060
+ flex: 1;
14061
+ min-width: 0;
14062
+ }
14063
+
14064
+ /* Source folders section */
14065
+ .create-project-folder-section {
14066
+ margin-top: 0.75rem;
14067
+ }
14068
+
14069
+ .create-project-folder-label {
14070
+ font-size: 0.78rem;
14071
+ font-weight: 500;
14072
+ color: var(--color-text-secondary);
14073
+ margin-bottom: 0.4rem;
14074
+ }
14075
+
14076
+ .create-project-folder-area {
14077
+ border: 1px solid var(--color-border-primary);
14078
+ border-radius: var(--radius-md);
14079
+ background: var(--color-bg-secondary);
14080
+ min-height: 52px;
14081
+ display: flex;
14082
+ align-items: center;
14083
+ justify-content: center;
14084
+ padding: 0.4rem 0.6rem;
14085
+ cursor: pointer;
14086
+ transition: border-color 0.15s, background 0.15s;
14087
+ }
14088
+ .create-project-folder-area:hover {
14089
+ border-color: var(--color-border-secondary);
14090
+ background: var(--color-bg-hover);
14091
+ }
14092
+
14093
+ .create-project-folder-empty {
14094
+ display: flex;
14095
+ flex-direction: column;
14096
+ align-items: center;
14097
+ gap: 0.25rem;
14098
+ color: var(--color-text-muted);
14099
+ font-size: 0.78rem;
14100
+ pointer-events: none;
14101
+ }
14102
+ .create-project-folder-empty svg {
14103
+ opacity: 0.5;
14104
+ width: 18px;
14105
+ height: 18px;
14106
+ }
14107
+
14108
+ /* Selected folder card */
14109
+ .create-project-folder-card {
14110
+ display: flex;
14111
+ align-items: center;
14112
+ gap: 0.4rem;
14113
+ width: 100%;
14114
+ color: var(--color-text-primary);
14115
+ font-size: 0.8rem;
14116
+ cursor: default;
14117
+ }
14118
+ .create-project-folder-card > svg {
14119
+ flex-shrink: 0;
14120
+ color: var(--color-accent-primary);
14121
+ width: 14px;
14122
+ height: 14px;
14123
+ }
14124
+ .create-project-folder-name {
14125
+ flex: 1;
14126
+ min-width: 0;
14127
+ overflow: hidden;
14128
+ text-overflow: ellipsis;
14129
+ white-space: nowrap;
14130
+ }
14131
+ .create-project-folder-remove {
14132
+ flex-shrink: 0;
14133
+ display: inline-flex;
14134
+ align-items: center;
14135
+ justify-content: center;
14136
+ width: 1.25rem;
14137
+ height: 1.25rem;
14138
+ border-radius: 4px;
14139
+ border: none;
14140
+ background: transparent;
14141
+ color: var(--color-text-muted);
14142
+ cursor: pointer;
14143
+ padding: 0;
14144
+ transition: background 0.12s, color 0.12s;
14145
+ }
14146
+ .create-project-folder-remove:hover {
14147
+ background: rgba(0, 0, 0, 0.09);
14148
+ color: var(--color-text-primary);
14149
+ }
14150
+
14151
+ /* ── Project picker popup (floating panel) ───────────────────────────────── */
14152
+ .project-picker-popup {
14153
+ display: none; /* hidden by default; JS shows it via style.display */
14154
+ position: fixed;
14155
+ z-index: 9999;
14156
+ background: var(--color-bg-primary);
14157
+ border: 1px solid var(--color-border);
14158
+ border-radius: var(--radius-md);
14159
+ box-shadow: 0 8px 24px rgba(0,0,0,0.18);
14160
+ padding: 0.75rem;
14161
+ user-select: none;
14162
+ }
14163
+
14164
+ /* "No color" option — grey with a diagonal slash */
14165
+ .project-picker-color-none {
14166
+ background: var(--color-bg-tertiary);
14167
+ position: relative;
14168
+ overflow: hidden;
14169
+ }
14170
+ .project-picker-color-none::after {
14171
+ content: "";
14172
+ position: absolute;
14173
+ inset: 0;
14174
+ background: linear-gradient(
14175
+ to bottom right,
14176
+ transparent calc(50% - 1px),
14177
+ var(--color-error) calc(50% - 1px),
14178
+ var(--color-error) calc(50% + 1px),
14179
+ transparent calc(50% + 1px)
14180
+ );
14181
+ }
14182
+
14183
+ /* Color row */
14184
+ .project-picker-colors {
14185
+ display: flex;
14186
+ flex-wrap: wrap;
14187
+ gap: 0.5rem;
14188
+ margin-bottom: 0.5rem;
14189
+ }
14190
+ .project-picker-color-option {
14191
+ width: 1.6rem;
14192
+ height: 1.6rem;
14193
+ border-radius: 50%;
14194
+ border: 2.5px solid transparent;
14195
+ cursor: pointer;
14196
+ padding: 0;
14197
+ transition: transform 0.1s, box-shadow 0.1s;
14198
+ flex-shrink: 0;
14199
+ }
14200
+ .project-picker-color-option:hover {
14201
+ transform: scale(1.15);
14202
+ }
14203
+ .project-picker-color-option--selected {
14204
+ box-shadow: 0 0 0 2px var(--color-bg-primary), 0 0 0 4px var(--color-text-primary);
14205
+ }
14206
+
14207
+ /* Divider */
14208
+ .project-picker-divider {
14209
+ height: 1px;
14210
+ background: var(--color-border);
14211
+ margin: 0.5rem 0;
14212
+ }
14213
+
14214
+ /* Icon grid */
14215
+ .project-picker-icons {
14216
+ display: grid;
14217
+ grid-template-columns: repeat(6, 1fr);
14218
+ gap: 0.25rem;
14219
+ }
14220
+ .project-picker-icon-option {
14221
+ display: inline-flex;
14222
+ align-items: center;
14223
+ justify-content: center;
14224
+ width: 2rem;
14225
+ height: 2rem;
14226
+ border-radius: var(--radius-sm);
14227
+ border: 1.5px solid transparent;
14228
+ background: transparent;
14229
+ color: var(--color-text-secondary);
14230
+ cursor: pointer;
14231
+ padding: 0;
14232
+ transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
14233
+ }
14234
+ .project-picker-icon-option:hover {
14235
+ background: var(--color-bg-hover);
14236
+ color: var(--color-text-primary);
14237
+ }
14238
+ .project-picker-icon-option--selected {
14239
+ background: var(--color-accent-subtle, rgba(236,72,153,0.12));
14240
+ border-color: var(--color-accent-primary);
14241
+ color: var(--color-accent-primary);
14242
+ }
14243
+ .project-picker-icon-option svg {
14244
+ pointer-events: none;
14245
+ }
14246
+
14247
+ /* Done button */
14248
+ .project-picker-footer {
14249
+ margin-top: 0.5rem;
14250
+ display: flex;
14251
+ justify-content: flex-end;
14252
+ }
14253
+ .project-picker-done-btn {
14254
+ font-size: 0.8125rem;
14255
+ padding: 0.3rem 0.875rem;
14256
+ border-radius: var(--radius-sm);
14257
+ border: 1px solid var(--color-border);
14258
+ background: var(--color-bg-secondary);
14259
+ color: var(--color-text-primary);
14260
+ cursor: pointer;
14261
+ transition: background var(--transition-fast);
14262
+ }
14263
+ .project-picker-done-btn:hover {
14264
+ background: var(--color-bg-hover);
14265
+ }
14266
+