1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/* body.dock is the STATIONARY full-surface DRAG HANDLE — it carries `drag: drag`
(so RmlUi emits dragstart/drag/dragend that our bind_drag reads) but it is
NEVER transformed. This is load-bearing: RmlUi projects a drag event's
mouse_x/mouse_y into the DRAGGED element's transformed coordinate frame, so if
the dragged element itself were translated by `slide` (as it was), the reported
drag x would feed back into `slide` and ping-pong between the finger position
and ~dock_width every frame (the flicker). Keeping the drag handle at identity
transform makes the reported coordinate the raw finger position. The MOVING
visual is div.panel below — a child that is NOT the drag element, so its
transform never enters the drag projection. body itself paints nothing (the
gradient lives on the panel); it is just the input-capture + drag-origin layer. */
body.dock {
width: 100%;
height: 100%;
drag: drag;
}
/* div.panel is the VALUE-DRIVEN moving visual: data-style-transform binds
translateX(slide px) (closed = -dock_width, open = 0). The gradient, padding,
flex layout and scroll live here, not on body. */
div.panel {
width: 100%;
height: 100%;
/* Use the SHADER-based linear-gradient (not the legacy horizontal-gradient,
which renders via interpolated vertex colours and shows hard 8-bit alpha
banding over light backgrounds). linear-gradient is computed per-pixel in
our GL3 fragment shader, which also applies ~1 LSB TPDF dither to break the
alpha-ramp banding as it fades to transparent. */
decorator: linear-gradient( to right, #000000ff, #00000000 );
padding: 8dp;
font-family: Noto Sans;
display: flex;
flex-direction: column;
align-items: center;
overflow-x: hidden;
overflow-y: auto;
}
/* DECLARATIVE EASING CARRIER for the C++ animator (d1 fix). This `transition` is
NOT animated by RmlUi: RmlUi only starts a CSS transition on a class/definition
change, and `slide` is driven through the inline data-style-transform above,
which RmlUi never animates. Instead the C++ SlideAnimator READS this transition
(duration + tween) via UiSurface::transition_timing("panel", "transform") and
drives slide_px_ itself, frame by frame — so editing the duration/tween here
hot-reloads the on-seat feel with no recompile. The element id="panel" is what
transition_timing looks the element up by. NOTE: RmlUi 6.2 has NO bare `linear`
keyword — use a named tween; `cubic-in-out` is the authored ease here. */
#panel {
transition: transform 0.36s cubic-in-out;
}
/* Hide both scrollbars (the rail scrolls, but no visible scrollbar). RmlUi
instances scrollbarvertical/scrollbarhorizontal elements; width/height 0 hides
them (verified pattern: vendored Samples effects_style.rcss / invader.rcss). */
div.panel scrollbarvertical {
width: 0dp;
}
div.panel scrollbarhorizontal {
height: 0dp;
}
/* The slot WRAPPER. margin:auto on this single flex item vertically centers the
card stack when it fits, and collapses to 0 free-space (top stays reachable,
no clipping) when the cards overflow — the correct flex-center+overflow
pattern (justify-content:center would strand/clip the top on overflow).
flex-shrink:0 so the stack keeps its natural height and the container scrolls. */
div.rail {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
margin: auto 0;
}
@keyframes slot-enter {
from {
opacity: 0;
transform: translateX(-12dp) scale(0.72);
}
to {
opacity: 1;
transform: translateX(0px) scale(1.0);
}
}
div.slot {
display: block;
position: relative;
width: 224dp;
height: 140dp;
min-height: 140dp;
margin-bottom: 8dp;
background-color: #2e2e32ff;
border-radius: 10dp;
overflow: hidden;
transform-origin: 0% 0%;
animation: slot-enter 0.16s cubic-out 1 normal;
}
div.slot div.thumb {
/* OVERSCAN the slot by 2dp on every side: RmlUi resolves the inset/percent
box anchored top-left, leaving the thumb ~2px short on the RIGHT so the
#2e2e32 slot placeholder peeked through there (diagnosed real-seat: the
sliver sampled as the placeholder, not the thumb). A negative inset makes
the thumb a few dp LARGER than the slot; the slot's rounded overflow:hidden
clips the overscan to the rounded card, so every edge is fully covered with
no placeholder peek and the corners stay rounded. cover/center keeps the
slightly-larger box fully covered + centered. */
display: block;
position: absolute;
left: -2dp;
top: -2dp;
right: -2dp;
bottom: -2dp;
}
div.slot span.title {
/* Title overlay INTENTIONALLY NOT RENDERED (user decision): the card is
thumbnail-only for now. display:none keeps the {{ row.title }} binding +
the bind_list_string("slots","title", …) getter LIVE and compiling so the
overlay can be re-enabled later by restoring `display: block`. The scrim
squared off the thumbnail's rounded bottom corners + protruded on the
right; hiding it lets all four corners round cleanly. */
display: none;
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 4dp 6dp;
background-color: #00000099;
color: #f2f2f2ff;
font-size: 13dp;
text-align: center;
}
|