anentrypoint-design 0.0.127 → 0.0.130

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.
package/app-shell.css CHANGED
@@ -9,6 +9,28 @@
9
9
  ============================================================ */
10
10
  * { box-sizing: border-box; }
11
11
  html, body { margin: 0; padding: 0; }
12
+
13
+ /* ============================================================
14
+ Accessibility — Skip Link
15
+ ============================================================ */
16
+ .skip-link {
17
+ position: absolute;
18
+ top: -40px;
19
+ left: 0;
20
+ background: var(--accent);
21
+ color: var(--accent-fg);
22
+ padding: 8px 16px;
23
+ text-decoration: none;
24
+ z-index: 100;
25
+ border-radius: var(--r-pill);
26
+ font-weight: 600;
27
+ font-size: var(--fs-sm);
28
+ }
29
+ .skip-link:focus {
30
+ top: 10px;
31
+ outline: 2px solid var(--fg-3);
32
+ outline-offset: 2px;
33
+ }
12
34
  body {
13
35
  background: var(--bg);
14
36
  color: var(--fg);
@@ -128,6 +150,11 @@ pre .n { color: var(--green-2); }
128
150
  min-height: 100vh;
129
151
  background: var(--bg);
130
152
  color: var(--fg);
153
+ /* Notched-device safe area padding (no-op on devices without notches) */
154
+ padding-top: env(safe-area-inset-top);
155
+ padding-bottom: env(safe-area-inset-bottom);
156
+ padding-left: env(safe-area-inset-left);
157
+ padding-right: env(safe-area-inset-right);
131
158
  }
132
159
 
133
160
  .app-topbar {
@@ -141,7 +168,10 @@ pre .n { color: var(--green-2); }
141
168
  .app-topbar nav { display: flex; gap: 4px; font-size: var(--fs-sm); }
142
169
  .app-topbar nav a {
143
170
  color: var(--fg-2);
144
- padding: 8px 14px;
171
+ padding: 12px 14px;
172
+ min-height: 44px;
173
+ display: flex;
174
+ align-items: center;
145
175
  border-radius: var(--r-pill);
146
176
  transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
147
177
  }
@@ -168,10 +198,18 @@ pre .n { color: var(--green-2); }
168
198
  }
169
199
  .app-search .icon { opacity: 0.6; }
170
200
  .app-search input {
171
- border: 0; outline: 0; background: transparent;
201
+ border: 0; background: transparent;
172
202
  font-family: inherit; font-size: inherit; color: var(--fg);
173
203
  width: 100%;
174
204
  }
205
+ .app-search input:focus-visible {
206
+ outline: 2px solid var(--accent);
207
+ outline-offset: 2px;
208
+ background: var(--bg-2);
209
+ border-radius: var(--r-pill);
210
+ padding-left: 8px;
211
+ padding-right: 8px;
212
+ }
175
213
 
176
214
  .app-crumb {
177
215
  padding: 0 var(--pad-x) 14px;
@@ -199,7 +237,8 @@ pre .n { color: var(--green-2); }
199
237
  .app-side a {
200
238
  display: grid; grid-template-columns: 18px 1fr auto;
201
239
  gap: 10px; align-items: center;
202
- padding: 10px 14px;
240
+ padding: 12px 14px;
241
+ min-height: 44px;
203
242
  border-radius: var(--r-pill);
204
243
  color: var(--fg-2);
205
244
  margin-bottom: 2px;
@@ -516,15 +555,152 @@ table tr.clickable:hover td { background: var(--bg-2); }
516
555
  font-family: inherit; font-size: var(--fs-sm);
517
556
  padding: 12px 16px;
518
557
  background: var(--bg); color: var(--fg);
519
- border: 0; border-radius: var(--r-2); outline: 0;
558
+ border: 0; border-radius: var(--r-2);
520
559
  box-shadow: inset 0 0 0 1px var(--rule);
521
560
  }
522
561
  .row-form input:focus,
523
562
  .row-form textarea:focus { box-shadow: inset 0 0 0 2px var(--accent); }
524
563
 
525
564
  /* ============================================================
526
- Responsive
565
+ Responsive Design — Mobile (480px), Tablet (1024px), Desktop (1440px+)
527
566
  ============================================================ */
567
+
568
+ /* ────────────────────────────────────────────────────────────────────
569
+ Mobile Portrait Breakpoint (480px and below)
570
+ ────────────────────────────────────────────────────────────────────── */
571
+ @media (max-width: 480px) {
572
+ /* App Layout */
573
+ .app-body { grid-template-columns: 1fr !important; }
574
+ .app-body.no-side { grid-template-columns: 1fr; }
575
+ .app-side-shell { border-right: 0; border-bottom: 1px solid var(--rule); }
576
+ .app-side {
577
+ padding: var(--space-3) var(--space-2);
578
+ font-size: var(--fs-xs);
579
+ flex-direction: row; flex-wrap: wrap; gap: var(--space-2);
580
+ }
581
+ .app-side .group {
582
+ width: 100%; font-size: var(--fs-micro); margin-bottom: 4px;
583
+ }
584
+ .app-side a {
585
+ flex: 1; min-width: 100px; padding: 12px 10px; gap: 6px;
586
+ grid-template-columns: 14px 1fr;
587
+ min-height: 44px;
588
+ }
589
+ .app-side a .glyph { font-size: 12px; }
590
+
591
+ /* Topbar Navigation */
592
+ .app-topbar {
593
+ grid-template-columns: 1fr auto;
594
+ gap: var(--space-2); padding: 12px var(--space-3);
595
+ }
596
+ .app-topbar nav a {
597
+ padding: 12px 10px;
598
+ min-height: 44px;
599
+ }
600
+ .app-topbar nav {
601
+ display: none; /* Hide full nav on very small screens */
602
+ }
603
+ .brand { font-size: var(--fs-tiny); font-weight: 600; }
604
+
605
+ /* Search */
606
+ .app-search {
607
+ display: none; /* Hide search on mobile unless explicitly pinned */
608
+ }
609
+
610
+ /* Main Content */
611
+ .app-main { padding: var(--space-4) var(--space-2); }
612
+ .app-main.narrow { max-width: 100%; margin: 0; }
613
+
614
+ /* Typography Scaling */
615
+ .t-hero { font-size: clamp(28px, 8vw, 48px); }
616
+ .t-mega { font-size: clamp(24px, 6vw, 42px); }
617
+ h1, .t-h1 { font-size: clamp(22px, 6vw, 36px); }
618
+ h2, .t-h2 { font-size: clamp(18px, 5vw, 28px); }
619
+ h3, .t-h3 { font-size: clamp(16px, 4.5vw, 24px); }
620
+
621
+ /* Panel & Row */
622
+ .panel { margin: 0 0 var(--space-3); }
623
+ .panel-head { padding: var(--space-3) var(--space-2); gap: var(--space-2); }
624
+ .panel-body { padding: var(--space-2); }
625
+
626
+ .row {
627
+ grid-template-columns: minmax(0, 1fr) auto !important;
628
+ gap: var(--space-2); padding: 12px 16px;
629
+ row-gap: 4px !important;
630
+ }
631
+ .row .sub { grid-column: 1 / -1; order: 3; }
632
+ .row .title { font-size: var(--fs-sm); }
633
+
634
+ /* Buttons */
635
+ .btn, .btn-primary, .btn-ghost {
636
+ padding: 11px 16px; font-size: var(--fs-tiny);
637
+ min-height: 44px; /* Touch target minimum */
638
+ }
639
+
640
+ /* File Grid */
641
+ .ds-file-grid {
642
+ display: grid;
643
+ grid-template-columns: 1fr;
644
+ gap: var(--space-2);
645
+ }
646
+ .ds-file-row {
647
+ grid-template-columns: 24px 1fr auto;
648
+ gap: 10px; padding: 10px 12px;
649
+ font-size: var(--fs-xs);
650
+ }
651
+ .ds-file-row .name { font-size: var(--fs-sm); }
652
+ .ds-file-row .size { font-size: var(--fs-micro); }
653
+
654
+ /* Chat */
655
+ .chat-stack { max-width: 100%; min-width: 0; }
656
+ .chat-bubble {
657
+ max-width: clamp(200px, 85vw, 320px);
658
+ padding: 10px 12px; font-size: var(--fs-sm);
659
+ }
660
+ .chat-avatar { width: 28px; height: 28px; font-size: 11px; }
661
+ .chat-msg:hover { padding: 4px 0; margin: 0; background: transparent; }
662
+ .chat-composer { padding: 8px; gap: 6px; }
663
+ .chat-composer textarea { padding: 10px 12px; font-size: var(--fs-sm); }
664
+ .chat-composer .send,
665
+ .chat-composer button { width: 40px; height: 40px; font-size: 16px; }
666
+
667
+ /* KPI Cards */
668
+ .kpi {
669
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
670
+ gap: var(--space-2);
671
+ }
672
+ .kpi-card { padding: var(--space-3); }
673
+ .kpi-card .num { font-size: clamp(22px, 5vw, 32px); }
674
+
675
+ /* Empty State */
676
+ .empty { padding: var(--space-5); font-size: var(--fs-xs); }
677
+
678
+ /* Form */
679
+ .row-form { gap: 10px; padding: var(--space-3); }
680
+ .row-form input,
681
+ .row-form textarea { padding: 11px 12px; font-size: var(--fs-sm); }
682
+
683
+ /* Hero Section */
684
+ .ds-hero { padding: var(--space-6) 0 var(--space-5); }
685
+ .ds-hero-title { font-size: clamp(28px, 7vw, 48px); max-width: 100%; }
686
+ .ds-hero-body { font-size: var(--fs-lg); max-width: 100%; }
687
+
688
+ /* Table Responsiveness */
689
+ table { font-size: var(--fs-xs); }
690
+ table th,
691
+ table td { padding: 10px 12px; }
692
+
693
+ /* CLI Block */
694
+ .cli {
695
+ flex-direction: column; align-items: flex-start; gap: 10px;
696
+ padding: 16px 12px; font-size: var(--fs-xs);
697
+ }
698
+ .cli .copy { padding: 6px 12px; font-size: var(--fs-micro); }
699
+ }
700
+
701
+ /* ────────────────────────────────────────────────────────────────────
702
+ Container Query Responsive (720px and below)
703
+ ────────────────────────────────────────────────────────────────────── */
528
704
  @container (max-width: 760px) {
529
705
  .app-body { grid-template-columns: 1fr !important; }
530
706
  .app-side-shell { border-right: 0; border-bottom: 1px solid var(--rule); }
@@ -534,25 +710,156 @@ table tr.clickable:hover td { background: var(--bg-2); }
534
710
  .row .sub { grid-column: 1 / -1; order: 3; }
535
711
  }
536
712
 
713
+ /* ────────────────────────────────────────────────────────────────────
714
+ Tablet Landscape Breakpoint (768px to 1024px)
715
+ ────────────────────────────────────────────────────────────────────── */
716
+ @media (min-width: 481px) and (max-width: 1024px) {
717
+ /* App Layout */
718
+ .app-body { grid-template-columns: 200px minmax(0, 1fr); }
719
+ .app-side {
720
+ padding: var(--space-4) var(--space-2);
721
+ font-size: var(--fs-xs);
722
+ flex-direction: column; gap: var(--space-3);
723
+ }
724
+ .app-side a {
725
+ padding: 12px 12px; gap: 8px;
726
+ grid-template-columns: 16px 1fr auto;
727
+ font-size: var(--fs-xs);
728
+ min-height: 44px;
729
+ }
730
+
731
+ /* Topbar Navigation */
732
+ .app-topbar {
733
+ grid-template-columns: auto 1fr auto;
734
+ gap: var(--space-3); padding: 12px var(--space-4);
735
+ }
736
+ .app-topbar nav {
737
+ display: flex; gap: 8px; font-size: var(--fs-xs);
738
+ flex-wrap: wrap;
739
+ }
740
+ .app-topbar nav a {
741
+ padding: 12px 12px; font-size: var(--fs-xs);
742
+ min-height: 44px;
743
+ }
744
+ .brand { font-size: var(--fs-sm); }
745
+
746
+ /* Search */
747
+ .app-search {
748
+ display: inline-flex;
749
+ max-width: 280px; font-size: var(--fs-xs);
750
+ padding: 8px 14px;
751
+ }
752
+
753
+ /* Main Content */
754
+ .app-main { padding: var(--space-6) var(--space-4); }
755
+ .app-main.narrow { max-width: 100%; }
756
+
757
+ /* Typography */
758
+ .t-hero { font-size: clamp(32px, 6.5cqi, 56px); }
759
+ .t-mega { font-size: clamp(28px, 5.5cqi, 80px); }
760
+ h1, .t-h1 { font-size: clamp(24px, 5cqi, 48px); }
761
+ h2, .t-h2 { font-size: clamp(20px, 4cqi, 36px); }
762
+ h3, .t-h3 { font-size: clamp(18px, 3.5cqi, 28px); }
763
+
764
+ /* File Grid — 2-3 columns on tablet */
765
+ .ds-file-grid {
766
+ display: grid;
767
+ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
768
+ gap: var(--space-3);
769
+ }
770
+ .ds-file-row {
771
+ grid-template-columns: 24px 1fr auto;
772
+ gap: 12px; padding: 12px 14px;
773
+ }
774
+
775
+ /* Chat Bubbles */
776
+ .chat-stack { max-width: min(75%, 420px); }
777
+ .chat-bubble {
778
+ max-width: clamp(220px, 75vw, 420px);
779
+ padding: 11px 14px; font-size: var(--fs-sm);
780
+ }
781
+ .chat-avatar { width: 32px; height: 32px; font-size: 12px; }
782
+
783
+ /* KPI Cards */
784
+ .kpi {
785
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
786
+ gap: var(--space-3);
787
+ }
788
+
789
+ /* Buttons */
790
+ .btn, .btn-primary, .btn-ghost {
791
+ padding: 12px 18px; font-size: var(--fs-sm);
792
+ }
793
+
794
+ /* Panel */
795
+ .panel-head { padding: var(--space-4) var(--space-4); }
796
+ .panel-body { padding: var(--space-2) var(--space-3); }
797
+
798
+ /* Hero */
799
+ .ds-hero { padding: var(--space-7) 0 var(--space-6); max-width: 100%; }
800
+ .ds-hero-title { font-size: clamp(32px, 6cqi, 56px); max-width: 100%; }
801
+
802
+ /* Row */
803
+ .row {
804
+ grid-template-columns: minmax(90px, 12ch) minmax(0, 1fr) auto;
805
+ gap: var(--space-2); padding: 14px 16px;
806
+ }
807
+ }
808
+
809
+ /* ────────────────────────────────────────────────────────────────────
810
+ Desktop Breakpoint Enhancements (1025px and up)
811
+ ────────────────────────────────────────────────────────────────────── */
812
+ @media (min-width: 1025px) {
813
+ /* File Grid — 3-4 columns on desktop */
814
+ .ds-file-grid {
815
+ display: grid;
816
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
817
+ gap: var(--space-4);
818
+ }
819
+
820
+ /* Chat Bubbles */
821
+ .chat-stack { max-width: min(70%, 480px); }
822
+ .chat-bubble {
823
+ max-width: clamp(240px, 70vw, 480px);
824
+ }
825
+
826
+ /* KPI Cards */
827
+ .kpi {
828
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
829
+ gap: var(--space-3);
830
+ }
831
+ }
832
+
537
833
  /* ============================================================
538
834
  Chat — minimal styles (placeholder for full chat surface)
539
835
  ============================================================ */
540
836
  .ds-chat { display: flex; flex-direction: column; gap: 12px; padding: var(--space-4); }
541
- .ds-chat-msg { padding: 12px 18px; background: var(--bg-2); border-radius: var(--r-3); max-width: 36em; }
837
+ .ds-chat-msg { padding: 12px 18px; background: var(--bg-2); border-radius: var(--r-3); max-width: min(90vw, 36em); }
542
838
  .ds-chat-msg.user { background: var(--accent); color: var(--accent-fg); align-self: flex-end; }
543
839
  .ds-chat-md { font-size: var(--fs-sm); line-height: 1.6; }
544
840
  .ds-chat-composer { display: flex; gap: 8px; padding: var(--space-4); }
545
- .ds-chat-composer input { flex: 1; padding: 13px 18px; background: var(--bg-2); border: 0; border-radius: var(--r-pill); font-family: inherit; font-size: var(--fs-sm); color: var(--fg); outline: 0; }
841
+ .ds-chat-composer input { flex: 1; padding: 13px 18px; background: var(--bg-2); border: 0; border-radius: var(--r-pill); font-family: inherit; font-size: var(--fs-sm); color: var(--fg); }
546
842
  .ds-chat-composer input:focus { box-shadow: inset 0 0 0 2px var(--accent); }
547
843
 
548
844
  /* ============================================================
549
- File surface — minimal placeholder
845
+ File surface — responsive grid + row layouts
550
846
  ============================================================ */
847
+
848
+ /* Default file grid — auto-responsive with CSS Grid */
849
+ .ds-file-grid {
850
+ display: grid;
851
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
852
+ gap: var(--space-4);
853
+ /* Responsive via container queries in media breakpoints below */
854
+ }
855
+
856
+ /* File row — linear layout (used in list view) */
551
857
  .ds-file-row {
552
858
  display: grid; grid-template-columns: 28px minmax(0, 1fr) auto auto;
553
859
  gap: 14px; align-items: center;
554
860
  padding: 12px 18px; background: var(--bg);
555
861
  border-radius: var(--r-2); color: var(--fg);
862
+ transition: background var(--dur-snap) var(--ease);
556
863
  }
557
864
  .ds-file-row + .ds-file-row { margin-top: 3px; }
558
865
  .ds-file-row:hover { background: var(--bg-2); }
@@ -565,10 +872,16 @@ table tr.clickable:hover td { background: var(--bg-2); }
565
872
  .ds-file-row[data-file-type="archive"] { border-left: 3px solid var(--flame); padding-left: 11px; }
566
873
  .ds-file-row[data-file-type="document"] { border-left: 3px solid var(--sun); padding-left: 11px; }
567
874
  .ds-file-row[data-file-type="other"] { border-left: 3px solid var(--fg-3); padding-left: 11px; }
568
- .ds-file-row .name { font-weight: 500; }
875
+ .ds-file-row .name { font-weight: 500; font-size: var(--fs-sm); }
569
876
  .ds-file-row .size { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); }
570
877
  .ds-file-row .time { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); }
571
878
 
879
+ /* File grid — data-columns attribute (explicit column override) */
880
+ .ds-file-grid[data-columns="1"] { grid-template-columns: 1fr; }
881
+ .ds-file-grid[data-columns="2"] { grid-template-columns: repeat(2, 1fr); }
882
+ .ds-file-grid[data-columns="3"] { grid-template-columns: repeat(3, 1fr); }
883
+ .ds-file-grid[data-columns="4"] { grid-template-columns: repeat(4, 1fr); }
884
+
572
885
  /* ============================================================
573
886
  Theme toggle (segmented + compact) — bound to src/theme.js
574
887
  ============================================================ */
@@ -643,7 +956,7 @@ table tr.clickable:hover td { background: var(--bg-2); }
643
956
  .chat-msg { display: flex; gap: 12px; align-items: flex-start; padding: 2px 0; position: relative; }
644
957
  .chat-msg.you { flex-direction: row-reverse; }
645
958
  .chat-msg.you .chat-stack { align-items: flex-end; }
646
- .chat-msg:hover { background: color-mix(in oklab, var(--fg) 1%, transparent); padding: 6px 8px; margin: -4px -8px; border-radius: 8px; transition: background 0.12s ease, padding 0.12s ease; }
959
+ .chat-msg:hover { background: color-mix(in oklab, var(--fg) 1%, transparent); padding: 2px 0; margin: 0; border-radius: 8px; transition: background var(--dur-base) var(--ease); }
647
960
 
648
961
  .chat-avatar {
649
962
  width: 36px; height: 36px; flex-shrink: 0;
@@ -654,7 +967,7 @@ table tr.clickable:hover td { background: var(--bg-2); }
654
967
  transition: transform 0.12s ease, box-shadow 0.12s ease;
655
968
  position: relative;
656
969
  }
657
- .chat-msg:hover .chat-avatar { transform: scale(1.08); box-shadow: 0 2px 8px color-mix(in oklab, var(--fg) 10%, transparent); }
970
+ .chat-msg:hover .chat-avatar { transform: scale(1.03); box-shadow: 0 1px 4px color-mix(in oklab, var(--fg) 6%, transparent); }
658
971
  .chat-msg.you .chat-avatar {
659
972
  background: color-mix(in oklab, var(--accent) 26%, var(--bg-3));
660
973
  color: var(--accent);
@@ -674,9 +987,10 @@ table tr.clickable:hover td { background: var(--bg-2); }
674
987
  border-radius: 14px; line-height: 1.55;
675
988
  word-wrap: break-word; overflow-wrap: anywhere;
676
989
  font-size: var(--fs-sm);
990
+ max-width: clamp(200px, 80vw, 480px);
677
991
  transition: transform 0.12s ease, box-shadow 0.12s ease;
678
992
  }
679
- .chat-msg:hover .chat-bubble { transform: translateY(-1px); box-shadow: 0 4px 16px color-mix(in oklab, var(--fg) 8%, transparent); }
993
+ .chat-msg:hover .chat-bubble { transform: translateY(-1px); box-shadow: 0 2px 8px color-mix(in oklab, var(--fg) 6%, transparent); transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease); }
680
994
  .chat-msg.you .chat-bubble { background: var(--accent); color: var(--accent-fg); }
681
995
  .chat-msg.aicat .chat-bubble {
682
996
  background: color-mix(in oklab, var(--mascot) 14%, var(--bg-2));
@@ -889,28 +1203,35 @@ table tr.clickable:hover td { background: var(--bg-2); }
889
1203
  .chat-typing { display: inline-flex; gap: 4px; align-items: center; }
890
1204
  .chat-typing span {
891
1205
  width: 6px; height: 6px; border-radius: 50%; background: var(--fg-3);
892
- animation: chat-typing-bounce 1.4s infinite ease-in-out;
893
- }
894
- .chat-typing span:nth-child(1) { animation-delay: 0s; }
895
- .chat-typing span:nth-child(2) { animation-delay: 0.18s; }
896
- .chat-typing span:nth-child(3) { animation-delay: 0.36s; }
897
- @keyframes chat-typing-bounce {
898
- 0%, 60%, 100% { transform: translateY(0); opacity: 0.55; }
899
- 30% { transform: translateY(-5px); opacity: 1; }
900
1206
  }
901
1207
 
902
- @keyframes chat-fade-in {
903
- from { opacity: 0; transform: translateY(8px); }
904
- to { opacity: 1; transform: translateY(0); }
1208
+ @media (prefers-reduced-motion: no-preference) {
1209
+ .chat-typing span {
1210
+ animation: chat-typing-bounce 1.4s infinite ease-in-out;
1211
+ }
1212
+ .chat-typing span:nth-child(1) { animation-delay: 0s; }
1213
+ .chat-typing span:nth-child(2) { animation-delay: 0.18s; }
1214
+ .chat-typing span:nth-child(3) { animation-delay: 0.36s; }
1215
+ @keyframes chat-typing-bounce {
1216
+ 0%, 60%, 100% { transform: translateY(0); opacity: 0.55; }
1217
+ 30% { transform: translateY(-5px); opacity: 1; }
1218
+ }
905
1219
  }
906
1220
 
907
- .chat-msg {
908
- animation: chat-fade-in 0.3s ease-out forwards;
1221
+ @media (prefers-reduced-motion: no-preference) {
1222
+ @keyframes chat-fade-in {
1223
+ from { opacity: 0; transform: translateY(8px); }
1224
+ to { opacity: 1; transform: translateY(0); }
1225
+ }
1226
+
1227
+ .chat-msg {
1228
+ animation: chat-fade-in 0.3s ease-out forwards;
1229
+ }
1230
+ .chat-msg:nth-child(1) { animation-delay: 0s; }
1231
+ .chat-msg:nth-child(2) { animation-delay: 0.05s; }
1232
+ .chat-msg:nth-child(3) { animation-delay: 0.1s; }
1233
+ .chat-msg:nth-child(n+4) { animation-delay: 0.15s; }
909
1234
  }
910
- .chat-msg:nth-child(1) { animation-delay: 0s; }
911
- .chat-msg:nth-child(2) { animation-delay: 0.05s; }
912
- .chat-msg:nth-child(3) { animation-delay: 0.1s; }
913
- .chat-msg:nth-child(n+4) { animation-delay: 0.15s; }
914
1235
 
915
1236
  .chat-composer {
916
1237
  display: flex; align-items: flex-end; gap: 8px;
@@ -923,7 +1244,7 @@ table tr.clickable:hover td { background: var(--bg-2); }
923
1244
  background: var(--bg-2); color: var(--fg);
924
1245
  border: 1px solid transparent; border-radius: var(--r-pill);
925
1246
  font-family: inherit; font-size: var(--fs-sm);
926
- line-height: 1.4; resize: none; outline: 0;
1247
+ line-height: 1.4; resize: none;
927
1248
  min-height: 44px; max-height: 200px;
928
1249
  }
929
1250
  .chat-composer textarea::placeholder { color: var(--fg-3); }
@@ -941,6 +1262,7 @@ table tr.clickable:hover td { background: var(--bg-2); }
941
1262
  display: inline-flex; align-items: center; justify-content: center;
942
1263
  flex-shrink: 0; font-family: var(--ff-body);
943
1264
  transition: background var(--dur-snap, .15s) var(--ease, ease), transform .1s ease;
1265
+ will-change: transform; contain: layout style paint;
944
1266
  }
945
1267
  .chat-composer .send:hover,
946
1268
  .chat-composer button:hover { transform: scale(1.04); }
@@ -986,7 +1308,6 @@ table tr.clickable:hover td { background: var(--bg-2); }
986
1308
  font-family: inherit;
987
1309
  font-size: var(--fs-sm);
988
1310
  color: var(--fg);
989
- outline: 0;
990
1311
  appearance: none;
991
1312
  background-image: linear-gradient(45deg, transparent 50%, var(--fg-3) 50%),
992
1313
  linear-gradient(135deg, var(--fg-3) 50%, transparent 50%);
@@ -1002,7 +1323,7 @@ table tr.clickable:hover td { background: var(--bg-2); }
1002
1323
  .chat-composer textarea {
1003
1324
  resize: none;
1004
1325
  overflow-y: auto;
1005
- transition: height 0.08s ease;
1326
+ transition: height var(--dur-snap) var(--ease);
1006
1327
  line-height: 1.5;
1007
1328
  }
1008
1329
  .chat-composer textarea:disabled {
@@ -1020,3 +1341,543 @@ table tr.clickable:hover td { background: var(--bg-2); }
1020
1341
  .chat-composer { padding: 8px; }
1021
1342
  .chat-composer textarea { padding: 10px 12px; }
1022
1343
  }
1344
+
1345
+ /* ── landscape orientation: reduce vertical space for composer ──────────── */
1346
+ @media (max-height: 500px) and (orientation: landscape) {
1347
+ .chat-composer { padding: 6px 0; }
1348
+ .chat-composer textarea { min-height: 36px; max-height: 120px; }
1349
+ .chat-composer .send, .chat-composer button { width: 36px; height: 36px; font-size: 14px; }
1350
+ }
1351
+
1352
+ /* ============================================================
1353
+ Enhanced UX: Component States, Drag-and-Drop, Context Menus
1354
+ Comprehensive improvements for perfect UX across all surfaces
1355
+ ============================================================ */
1356
+
1357
+ /* ────────────────────────────────────────────────────────────
1358
+ Component States — Disabled, Loading, Error, Success
1359
+ ────────────────────────────────────────────────────────────── */
1360
+
1361
+ /* Disabled state for all interactive elements */
1362
+ .btn:disabled, .btn-primary:disabled, .btn-ghost:disabled,
1363
+ button:disabled, [disabled] {
1364
+ opacity: 0.6;
1365
+ cursor: not-allowed;
1366
+ pointer-events: none;
1367
+ }
1368
+
1369
+ /* Loading state — spinning indicator */
1370
+ @keyframes spinner-rotate {
1371
+ from { transform: rotate(0deg); }
1372
+ to { transform: rotate(360deg); }
1373
+ }
1374
+ .loading { position: relative; }
1375
+ .loading::after {
1376
+ content: '';
1377
+ position: absolute; top: 50%; right: 12px;
1378
+ width: 16px; height: 16px;
1379
+ border: 2px solid var(--bg-3);
1380
+ border-top-color: var(--accent);
1381
+ border-radius: 50%;
1382
+ animation: spinner-rotate 0.8s linear infinite;
1383
+ }
1384
+
1385
+ /* Error state */
1386
+ .error, [data-state="error"],
1387
+ .row.error, input.error,
1388
+ textarea.error {
1389
+ border-color: var(--warn) !important;
1390
+ background-color: color-mix(in oklab, var(--warn) 6%, var(--bg));
1391
+ }
1392
+ .error::placeholder { color: color-mix(in oklab, var(--warn) 60%, var(--fg-3)); }
1393
+
1394
+ /* Success state */
1395
+ .success, [data-state="success"],
1396
+ .row.success { background-color: color-mix(in oklab, var(--green-2) 6%, var(--bg)); }
1397
+
1398
+ /* Readonly state */
1399
+ [readonly], .readonly {
1400
+ background: var(--bg-2);
1401
+ cursor: default;
1402
+ opacity: 0.8;
1403
+ }
1404
+
1405
+ /* ────────────────────────────────────────────────────────────
1406
+ Enhanced Button Micro-Interactions
1407
+ ────────────────────────────────────────────────────────────── */
1408
+
1409
+ /* Button scale feedback on active */
1410
+ .btn:active:not(:disabled),
1411
+ .btn-primary:active:not(:disabled),
1412
+ .btn-ghost:active:not(:disabled),
1413
+ button:active:not(:disabled) {
1414
+ transform: scale(0.98);
1415
+ }
1416
+
1417
+ /* Enhanced hover transitions */
1418
+ .btn, .btn-primary, .btn-ghost,
1419
+ button, a.row, .row,
1420
+ .chip, [role="button"],
1421
+ input[type="checkbox"], input[type="radio"] {
1422
+ transition: all var(--dur-snap) var(--ease);
1423
+ will-change: background-color, color, transform;
1424
+ }
1425
+
1426
+ /* Prevent double-tap zoom on buttons (iOS) */
1427
+ .btn, .btn-primary, .btn-ghost, button {
1428
+ -webkit-user-select: none;
1429
+ -webkit-tap-highlight-color: transparent;
1430
+ -webkit-touch-callout: none;
1431
+ }
1432
+
1433
+ /* ────────────────────────────────────────────────────────────
1434
+ Drag-and-Drop Styles
1435
+ ────────────────────────────────────────────────────────────── */
1436
+
1437
+ /* Draggable element */
1438
+ [draggable="true"], .draggable {
1439
+ cursor: grab;
1440
+ user-select: none;
1441
+ }
1442
+ [draggable="true"]:active { cursor: grabbing; }
1443
+
1444
+ /* Drag-over state */
1445
+ .drag-over {
1446
+ background: color-mix(in oklab, var(--accent) 12%, var(--bg));
1447
+ border: 2px dashed var(--accent);
1448
+ box-shadow: inset 0 0 0 1px var(--accent);
1449
+ }
1450
+
1451
+ /* Drag-ghost (semi-transparent dragging element) */
1452
+ .drag-ghost {
1453
+ opacity: 0.5;
1454
+ transform: rotate(2deg) scale(0.95);
1455
+ }
1456
+
1457
+ /* Drop-zone indicator */
1458
+ .drop-zone {
1459
+ border: 2px dashed var(--rule-strong);
1460
+ border-radius: var(--r-2);
1461
+ padding: var(--space-4);
1462
+ background: color-mix(in oklab, var(--accent) 4%, var(--bg));
1463
+ min-height: 120px;
1464
+ display: flex; align-items: center; justify-content: center;
1465
+ text-align: center; color: var(--fg-3);
1466
+ transition: all var(--dur-snap) var(--ease);
1467
+ }
1468
+ .drop-zone.active {
1469
+ border-color: var(--accent);
1470
+ background: color-mix(in oklab, var(--accent) 10%, var(--bg));
1471
+ color: var(--accent);
1472
+ }
1473
+
1474
+ /* List item reorder indicator */
1475
+ .list-item.dragging { opacity: 0.5; }
1476
+ .list-item.drag-before::before,
1477
+ .list-item.drag-after::after {
1478
+ content: '';
1479
+ position: absolute;
1480
+ left: 0; right: 0; height: 2px;
1481
+ background: var(--accent);
1482
+ animation: pulse-line 0.6s ease-in-out infinite;
1483
+ }
1484
+ .list-item.drag-before::before { top: -2px; }
1485
+ .list-item.drag-after::after { bottom: -2px; }
1486
+
1487
+ @keyframes pulse-line {
1488
+ 0%, 100% { opacity: 0.3; }
1489
+ 50% { opacity: 1; }
1490
+ }
1491
+
1492
+ /* ────────────────────────────────────────────────────────────
1493
+ Context Menu Styles
1494
+ ────────────────────────────────────────────────────────────── */
1495
+
1496
+ .ds-context-menu {
1497
+ position: absolute;
1498
+ background: var(--bg-2);
1499
+ border: 1px solid var(--rule);
1500
+ border-radius: var(--r-2);
1501
+ box-shadow: 0 10px 40px color-mix(in oklab, var(--fg) 20%, transparent);
1502
+ min-width: 160px;
1503
+ z-index: calc(var(--z-overlay, 1000) + 1);
1504
+ padding: 4px 0;
1505
+ animation: context-menu-in 0.15s ease-out;
1506
+ }
1507
+
1508
+ @keyframes context-menu-in {
1509
+ from {
1510
+ opacity: 0;
1511
+ transform: scale(0.95) translateY(-4px);
1512
+ }
1513
+ to {
1514
+ opacity: 1;
1515
+ transform: scale(1) translateY(0);
1516
+ }
1517
+ }
1518
+
1519
+ .ds-context-menu-item {
1520
+ display: flex; align-items: center; gap: 10px;
1521
+ padding: 10px 14px;
1522
+ cursor: pointer;
1523
+ color: var(--fg);
1524
+ font-size: var(--fs-sm);
1525
+ transition: background var(--dur-snap) var(--ease);
1526
+ }
1527
+ .ds-context-menu-item:hover {
1528
+ background: var(--bg-3);
1529
+ color: var(--accent);
1530
+ }
1531
+ .ds-context-menu-item:active {
1532
+ background: color-mix(in oklab, var(--accent) 20%, var(--bg-3));
1533
+ }
1534
+ .ds-context-menu-item.danger {
1535
+ color: var(--warn);
1536
+ }
1537
+ .ds-context-menu-item.danger:hover {
1538
+ background: color-mix(in oklab, var(--warn) 12%, var(--bg));
1539
+ }
1540
+ .ds-context-menu-divider {
1541
+ height: 1px;
1542
+ background: var(--rule);
1543
+ margin: 4px 0;
1544
+ }
1545
+ .ds-context-menu-icon {
1546
+ width: 16px; height: 16px;
1547
+ flex-shrink: 0;
1548
+ opacity: 0.7;
1549
+ }
1550
+
1551
+ /* Context menu trigger indicator */
1552
+ [data-has-context-menu] {
1553
+ cursor: context-menu;
1554
+ }
1555
+
1556
+ /* ────────────────────────────────────────────────────────────
1557
+ Enhanced Form Inputs
1558
+ ────────────────────────────────────────────────────────────── */
1559
+
1560
+ input[type="text"],
1561
+ input[type="email"],
1562
+ input[type="password"],
1563
+ input[type="number"],
1564
+ textarea,
1565
+ select {
1566
+ transition: background var(--dur-snap) var(--ease),
1567
+ border-color var(--dur-snap) var(--ease),
1568
+ box-shadow var(--dur-snap) var(--ease);
1569
+ }
1570
+
1571
+ input[type="text"]::placeholder,
1572
+ input[type="email"]::placeholder,
1573
+ input[type="password"]::placeholder,
1574
+ input[type="number"]::placeholder,
1575
+ textarea::placeholder {
1576
+ color: var(--fg-3);
1577
+ }
1578
+
1579
+ /* Clear button for text inputs */
1580
+ input[type="text"]:not(:placeholder-shown) + .input-clear,
1581
+ input[type="email"]:not(:placeholder-shown) + .input-clear,
1582
+ input[type="password"]:not(:placeholder-shown) + .input-clear {
1583
+ display: inline-flex;
1584
+ }
1585
+
1586
+ .input-clear {
1587
+ display: none;
1588
+ align-items: center; justify-content: center;
1589
+ width: 32px; height: 32px;
1590
+ cursor: pointer;
1591
+ color: var(--fg-3);
1592
+ background: transparent;
1593
+ border: 0;
1594
+ padding: 0;
1595
+ margin-right: 8px;
1596
+ border-radius: var(--r-1);
1597
+ transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
1598
+ }
1599
+ .input-clear:hover {
1600
+ background: var(--bg-2);
1601
+ color: var(--fg);
1602
+ }
1603
+
1604
+ /* ────────────────────────────────────────────────────────────
1605
+ Accessibility Enhancements
1606
+ ────────────────────────────────────────────────────────────── */
1607
+
1608
+ /* Enhanced focus-visible for all interactive elements */
1609
+ [role="button"]:focus-visible,
1610
+ [role="link"]:focus-visible,
1611
+ [role="tab"]:focus-visible,
1612
+ .row:focus-visible,
1613
+ .row[tabindex]:focus-visible {
1614
+ outline: 2px solid var(--accent);
1615
+ outline-offset: 2px;
1616
+ }
1617
+
1618
+ /* Skip to main content link */
1619
+ .skip-to-main {
1620
+ position: absolute; top: -40px; left: 0;
1621
+ background: var(--accent); color: var(--accent-fg);
1622
+ padding: 8px 16px; border-radius: var(--r-1);
1623
+ text-decoration: none; z-index: var(--z-overlay, 1000);
1624
+ }
1625
+ .skip-to-main:focus { top: 10px; }
1626
+
1627
+ /* Reduced motion preferences */
1628
+ @media (prefers-reduced-motion: reduce) {
1629
+ * {
1630
+ animation-duration: 0.01ms !important;
1631
+ animation-iteration-count: 1 !important;
1632
+ transition-duration: 0.01ms !important;
1633
+ }
1634
+ }
1635
+
1636
+ /* ────────────────────────────────────────────────────────────
1637
+ Performance: GPU Acceleration & Paint Optimization
1638
+ ────────────────────────────────────────────────────────────── */
1639
+
1640
+ /* Promote hover-interactive elements to compositing layer */
1641
+ .btn:hover, .btn-primary:hover, .btn-ghost:hover,
1642
+ a:hover, .row:hover,
1643
+ button:hover, [role="button"]:hover {
1644
+ transform: translateZ(0);
1645
+ }
1646
+
1647
+ /* Contain layout repaints on self-contained components */
1648
+ .panel, .row, .chip, .btn, button {
1649
+ contain: layout style paint;
1650
+ }
1651
+
1652
+ /* ────────────────────────────────────────────────────────────
1653
+ Mobile Touch Optimizations
1654
+ ────────────────────────────────────────────────────────────── */
1655
+
1656
+ @media (hover: none) and (pointer: coarse) {
1657
+ /* Mobile devices: larger touch targets, faster responses */
1658
+ .btn, .btn-primary, .btn-ghost,
1659
+ button, a.row, [role="button"] {
1660
+ min-height: 48px;
1661
+ min-width: 48px;
1662
+ padding: 12px 20px;
1663
+ }
1664
+
1665
+ /* Remove hover effects on touch devices (use active instead) */
1666
+ .btn:hover, .btn-primary:hover, .btn-ghost:hover {
1667
+ background-color: inherit;
1668
+ }
1669
+
1670
+ /* Momentum scrolling for iOS */
1671
+ .app-side, .panel, .row {
1672
+ -webkit-overflow-scrolling: touch;
1673
+ }
1674
+
1675
+ /* Long-press feedback for drag-enabled items */
1676
+ [draggable="true"], .draggable {
1677
+ -webkit-user-select: none;
1678
+ -webkit-touch-callout: none;
1679
+ }
1680
+ }
1681
+
1682
+ /* ────────────────────────────────────────────────────────────
1683
+ Theme Transition Smoothness
1684
+ ────────────────────────────────────────────────────────────── */
1685
+
1686
+ html {
1687
+ transition: background-color var(--dur-base) var(--ease),
1688
+ color var(--dur-base) var(--ease);
1689
+ }
1690
+
1691
+ body {
1692
+ transition: background-color var(--dur-base) var(--ease),
1693
+ color var(--dur-base) var(--ease);
1694
+ }
1695
+
1696
+ /* ────────────────────────────────────────────────────────────
1697
+ Empty State & Loading States
1698
+ ────────────────────────────────────────────────────────────── */
1699
+
1700
+ .empty-state {
1701
+ display: flex; flex-direction: column; align-items: center; gap: var(--space-4);
1702
+ padding: var(--space-8) var(--space-4);
1703
+ text-align: center; color: var(--fg-3);
1704
+ }
1705
+ .empty-state-icon {
1706
+ font-size: 48px; opacity: 0.4;
1707
+ }
1708
+ .empty-state-title {
1709
+ font-size: var(--fs-lg); font-weight: 600; color: var(--fg-2);
1710
+ }
1711
+ .empty-state-body {
1712
+ font-size: var(--fs-sm); max-width: 40ch;
1713
+ }
1714
+
1715
+ /* Skeleton loading state */
1716
+ .skeleton {
1717
+ background: linear-gradient(
1718
+ 90deg,
1719
+ var(--bg-2) 0%,
1720
+ var(--bg-3) 50%,
1721
+ var(--bg-2) 100%
1722
+ );
1723
+ background-size: 200% 100%;
1724
+ animation: skeleton-load 1.5s infinite;
1725
+ border-radius: var(--r-2);
1726
+ }
1727
+
1728
+ @keyframes skeleton-load {
1729
+ 0% { background-position: 200% 0; }
1730
+ 100% { background-position: -200% 0; }
1731
+ }
1732
+
1733
+ .skeleton-line { height: 12px; margin-bottom: 12px; }
1734
+ .skeleton-title { height: 24px; margin-bottom: 16px; width: 60%; }
1735
+
1736
+ /* ────────────────────────────────────────────────────────────
1737
+ Toast Notification Styles
1738
+ ────────────────────────────────────────────────────────────── */
1739
+
1740
+ .toast {
1741
+ position: fixed;
1742
+ bottom: 24px; right: 24px;
1743
+ background: var(--bg-2);
1744
+ border: 1px solid var(--rule);
1745
+ border-radius: var(--r-2);
1746
+ padding: var(--space-3) var(--space-4);
1747
+ max-width: 320px;
1748
+ box-shadow: 0 10px 40px color-mix(in oklab, var(--fg) 20%, transparent);
1749
+ animation: toast-slide-in 0.3s ease-out;
1750
+ z-index: calc(var(--z-overlay, 1000) + 10);
1751
+ }
1752
+
1753
+ @keyframes toast-slide-in {
1754
+ from {
1755
+ opacity: 0;
1756
+ transform: translateX(400px);
1757
+ }
1758
+ to {
1759
+ opacity: 1;
1760
+ transform: translateX(0);
1761
+ }
1762
+ }
1763
+
1764
+ .toast.error { border-color: var(--warn); }
1765
+ .toast.success { border-color: var(--green-2); }
1766
+ .toast.warning { border-color: var(--sun); }
1767
+
1768
+ @media (max-width: 480px) {
1769
+ .toast {
1770
+ bottom: 16px; right: 16px; left: 16px;
1771
+ max-width: none;
1772
+ }
1773
+ }
1774
+
1775
+ /* ============================================================
1776
+ Spinner — animated loading indicator
1777
+ ============================================================ */
1778
+ .ds-spinner {
1779
+ display: inline-flex;
1780
+ gap: 4px;
1781
+ align-items: center;
1782
+ height: 16px;
1783
+ }
1784
+ .ds-spinner span {
1785
+ width: 4px;
1786
+ height: 4px;
1787
+ border-radius: 50%;
1788
+ background: var(--accent);
1789
+ animation: ds-bounce 1.4s infinite ease-in-out;
1790
+ }
1791
+ .ds-spinner span:nth-child(1) { animation-delay: 0s; }
1792
+ .ds-spinner span:nth-child(2) { animation-delay: 0.18s; }
1793
+ .ds-spinner span:nth-child(3) { animation-delay: 0.36s; }
1794
+
1795
+ .ds-spinner-lg { height: 24px; gap: 6px; }
1796
+ .ds-spinner-lg span { width: 6px; height: 6px; }
1797
+
1798
+ .ds-spinner-sm { height: 12px; gap: 2px; }
1799
+ .ds-spinner-sm span { width: 2px; height: 2px; }
1800
+
1801
+ @keyframes ds-bounce {
1802
+ 0%, 80%, 100% { transform: translateY(0); }
1803
+ 40% { transform: translateY(-8px); }
1804
+ }
1805
+
1806
+ /* ============================================================
1807
+ Skeleton — animated loading placeholder
1808
+ ============================================================ */
1809
+ .ds-skeleton-group {
1810
+ display: flex;
1811
+ flex-direction: column;
1812
+ gap: var(--space-2);
1813
+ }
1814
+ .ds-skeleton {
1815
+ background: linear-gradient(90deg, var(--bg-2) 25%, var(--bg-3) 50%, var(--bg-2) 75%);
1816
+ background-size: 200% 100%;
1817
+ animation: ds-shimmer 1.5s infinite;
1818
+ border-radius: var(--r-1);
1819
+ }
1820
+
1821
+ @keyframes ds-shimmer {
1822
+ 0% { background-position: 200% 0; }
1823
+ 100% { background-position: -200% 0; }
1824
+ }
1825
+
1826
+ /* ============================================================
1827
+ Alert — contextual message banner
1828
+ ============================================================ */
1829
+ .ds-alert {
1830
+ display: flex;
1831
+ gap: var(--space-3);
1832
+ align-items: flex-start;
1833
+ padding: var(--space-3) var(--space-4);
1834
+ border-radius: var(--r-1);
1835
+ background: var(--panel-1);
1836
+ border: 1px solid var(--rule-strong);
1837
+ color: var(--fg);
1838
+ }
1839
+
1840
+ .ds-alert-info { --alert-tone: var(--sky); }
1841
+ .ds-alert-success { --alert-tone: var(--green); }
1842
+ .ds-alert-warn { --alert-tone: var(--sun); }
1843
+ .ds-alert-error { --alert-tone: var(--warn); }
1844
+
1845
+ .ds-alert-icon {
1846
+ flex-shrink: 0;
1847
+ color: var(--alert-tone);
1848
+ font-weight: 600;
1849
+ min-width: 20px;
1850
+ text-align: center;
1851
+ }
1852
+
1853
+ .ds-alert-content {
1854
+ flex: 1;
1855
+ display: flex;
1856
+ flex-direction: column;
1857
+ gap: 4px;
1858
+ }
1859
+
1860
+ .ds-alert-title {
1861
+ font-weight: 500;
1862
+ font-size: var(--fs-sm);
1863
+ }
1864
+
1865
+ .ds-alert-message {
1866
+ font-size: var(--fs-sm);
1867
+ color: var(--fg-2);
1868
+ }
1869
+
1870
+ .ds-alert-dismiss {
1871
+ flex-shrink: 0;
1872
+ background: none;
1873
+ border: none;
1874
+ cursor: pointer;
1875
+ color: var(--fg-3);
1876
+ padding: 0;
1877
+ font-size: 14px;
1878
+ line-height: 1;
1879
+ min-width: 20px;
1880
+ text-align: center;
1881
+ transition: color var(--dur-snap) var(--ease);
1882
+ }
1883
+ .ds-alert-dismiss:hover { color: var(--fg); }