estreui 1.2.6 → 1.4.0

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.
@@ -1397,6 +1397,7 @@ class EstreComponent extends EstrePageHostHandle {
1397
1397
  case "menu":
1398
1398
  case "overlay":
1399
1399
  case "header":
1400
+ case "panel":
1400
1401
  return false;
1401
1402
  }
1402
1403
  }
@@ -1793,6 +1794,53 @@ class EstreMenuComponent extends EstreComponent {
1793
1794
 
1794
1795
 
1795
1796
 
1797
+ /**
1798
+ * Component page handle for overwatchPanel sections (quickPanel, timeline).
1799
+ * Sections live inside the panel's dynamic_section_block and switch by horizontal scroll-snap;
1800
+ * opening or closing the whole panel is a shell-level operation on estreUi.
1801
+ */
1802
+ class EstrePanelComponent extends EstreComponent {
1803
+ // constants
1804
+ get sectionBound() { return "panel"; };
1805
+
1806
+ // class property
1807
+ static components = {};
1808
+ static componentList = [];
1809
+
1810
+
1811
+ constructor(component, instanceOrigin) {
1812
+ super(component, instanceOrigin);
1813
+ }
1814
+
1815
+ release(remove) {
1816
+ return super.release(remove);
1817
+ }
1818
+
1819
+ init(intent) {
1820
+ super.init(intent);
1821
+ return this;
1822
+ }
1823
+
1824
+ register() {
1825
+ return EstrePanelComponent.register(this);
1826
+ }
1827
+
1828
+ unregister() {
1829
+ EstrePanelComponent.unregister(this);
1830
+ }
1831
+
1832
+ show(isRequest = true, setFocus = true) {
1833
+ if (isRequest) {
1834
+ return estreUi.showOverwatchPanelSection(this.id);
1835
+ } else super.show(false, setFocus);
1836
+ }
1837
+
1838
+ // close() falls through to super — dismissing an individual panel section is not meaningful;
1839
+ // call estreUi.closeOverwatchPanel() to close the shell.
1840
+ }
1841
+
1842
+
1843
+
1796
1844
  /**
1797
1845
  * Component page handle for header sections
1798
1846
  */
@@ -3675,7 +3723,147 @@ class EstreUiPage {
3675
3723
 
3676
3724
  },
3677
3725
 
3678
- "$i&o=notification#noti@noti^": class extends EstrePageHandler { },
3726
+ "$i&o=notification#noti@noti^": class extends EstrePageHandler {
3727
+ $postBlock;
3728
+ $mainIconPlace;
3729
+ $subIconPlace;
3730
+ $titleLine;
3731
+ $subtitleLine;
3732
+ $contentLine;
3733
+ swipeHandler;
3734
+ #closeTimer;
3735
+ #closing = false;
3736
+
3737
+ #applyIntentToBlock(intent) {
3738
+ const data = intent?.data ?? {};
3739
+ this.$mainIconPlace.toggle(data.largeIconSrc != null && data.largeIconSrc !== "");
3740
+ this.$subIconPlace.toggle(data.iconSrc != null && data.iconSrc !== "");
3741
+ this.$titleLine.toggle(data.contentTitle != null && data.contentTitle !== "");
3742
+ this.$subtitleLine.toggle(data.subtitle != null && data.subtitle !== "");
3743
+ this.$contentLine.toggle(data.content != null && data.content !== "");
3744
+ }
3745
+
3746
+ #resetCloseTimer(handle) {
3747
+ if (this.#closeTimer != null) {
3748
+ clearTimeout(this.#closeTimer);
3749
+ this.#closeTimer = null;
3750
+ }
3751
+ const showTime = handle.intent?.data?.showTime ?? EstreNotificationManager.defaultShowTime;
3752
+ this.#closeTimer = setTimeout(_ => this.#beginClose(handle), showTime);
3753
+ }
3754
+
3755
+ #beginClose(handle) {
3756
+ if (this.#closing) return;
3757
+ this.#closing = true;
3758
+ if (this.#closeTimer != null) {
3759
+ clearTimeout(this.#closeTimer);
3760
+ this.#closeTimer = null;
3761
+ }
3762
+
3763
+ if (!EstreNotificationManager.hasQueued) {
3764
+ handle.close();
3765
+ return;
3766
+ }
3767
+
3768
+ const $block = this.$postBlock;
3769
+ const blockEl = $block[0];
3770
+ if (blockEl == null) { handle.close(); return; }
3771
+ const $article = $block.parent();
3772
+ const articleEl = $article[0];
3773
+ const rect = blockEl.getBoundingClientRect();
3774
+ const articleRect = articleEl.getBoundingClientRect();
3775
+ const $ghost = $block.clone(false).removeClass("banner_incoming");
3776
+ $ghost.addClass("banner_ghost_exit");
3777
+ $ghost.css({
3778
+ position: "absolute",
3779
+ left: (rect.left - articleRect.left) + "px",
3780
+ top: (rect.top - articleRect.top) + "px",
3781
+ width: rect.width + "px",
3782
+ margin: 0,
3783
+ pointerEvents: "none",
3784
+ });
3785
+ $article.append($ghost);
3786
+ setTimeout(() => $ghost.remove(), 550);
3787
+
3788
+ $block.css({ visibility: "hidden", pointerEvents: "none" });
3789
+
3790
+ EstreNotificationManager.beginCheckOut(handle.intent);
3791
+ }
3792
+
3793
+ onBring(handle) {
3794
+ const $host = handle.$host;
3795
+ this.$postBlock = $host.find(".post_block");
3796
+ this.$mainIconPlace = this.$postBlock.children(".icon_place");
3797
+ this.$titleLine = this.$postBlock.find("> .content_place > .title_line");
3798
+ this.$subtitleLine = this.$postBlock.find("> .content_place > .subtitle_line");
3799
+ this.$contentLine = this.$postBlock.find("> .content_place > .content_area > .content_place");
3800
+ this.$subIconPlace = this.$postBlock.find("> .content_place > .content_area > .icon_place");
3801
+
3802
+ this.#applyIntentToBlock(handle.intent);
3803
+
3804
+ EstreNotificationManager.current = handle.intent;
3805
+ if (window.isVerbosely) console.log("pushed", handle.intent);
3806
+ }
3807
+
3808
+ onOpen(handle) {
3809
+ this.#closing = false;
3810
+ this.$postBlock.click((e) => {
3811
+ e.preventDefault();
3812
+
3813
+ if (window.isVerbosely) console.log("clicked: ", handle.intent);
3814
+ handle.intent?.onTakeInteraction?.(handle.intent);
3815
+ this.#beginClose(handle);
3816
+
3817
+ return false;
3818
+ });
3819
+
3820
+ const self = this;
3821
+ this.swipeHandler = new EstreSwipeHandler(this.$postBlock)
3822
+ .setStopPropagation()
3823
+ .setPreventDefault()
3824
+ .unuseX()
3825
+ .setThresholdY(1)
3826
+ .setDropStrayed(false)
3827
+ .setResponseBound(this.$postBlock)
3828
+ .setOnUp(function (grabX, grabY, handled, canceled, directed) {
3829
+ if (!handled) return;
3830
+ if (this.handledDirection === "up" && Math.abs(grabY) > 20) {
3831
+ self.#beginClose(handle);
3832
+ } else if (this.handledDirection === "down" && Math.abs(grabY) > 40) {
3833
+ handle.intent?.onTakeInteraction?.(handle.intent);
3834
+ self.#beginClose(handle);
3835
+ }
3836
+ });
3837
+
3838
+ this.#resetCloseTimer(handle);
3839
+ if (window.isVerbosely) console.log("showing: ", handle.intent);
3840
+ }
3841
+
3842
+ onIntentUpdated(handle, intent) {
3843
+ // Queue-chain handover: previous banner's exit is playing on a
3844
+ // detached ghost clone; this article reuses the same DOM with
3845
+ // fresh content + a restart-triggered enter animation.
3846
+ this.#closing = false;
3847
+ if (intent?.data != null) this.#applyIntentToBlock(intent);
3848
+ EstreNotificationManager.current = handle.intent;
3849
+
3850
+ const $block = this.$postBlock;
3851
+ $block.css({ visibility: "", pointerEvents: "" });
3852
+ $block.removeClass("banner_incoming");
3853
+ void $block[0]?.offsetWidth;
3854
+ $block.addClass("banner_incoming");
3855
+
3856
+ this.#resetCloseTimer(handle);
3857
+ }
3858
+
3859
+ onClose(handle) {
3860
+ if (this.#closeTimer != null) {
3861
+ clearTimeout(this.#closeTimer);
3862
+ this.#closeTimer = null;
3863
+ }
3864
+ EstreNotificationManager.checkOut(handle.intent);
3865
+ }
3866
+ },
3679
3867
  "$i&o=notification#note@note^": class extends EstrePageHandler {
3680
3868
  $postBlock;
3681
3869
 
@@ -4208,7 +4396,7 @@ class EstreUiPage {
4208
4396
  if (this.#sectionBound == null) {
4209
4397
  const $componentHost = $component.closest("main, nav, header, footer");
4210
4398
  const hostId = $componentHost.attr("id");
4211
- const sectionBound = hostId == "staticDoc" ? "main" : (hostId == "instantDoc" ? "blind" : (hostId == "managedOverlay" ? "overlay" : (hostId == "mainMenu" ? "menu" : (hostId == "fixedTop" ? "header" : null))));
4399
+ const sectionBound = hostId == "staticDoc" ? "main" : (hostId == "instantDoc" ? "blind" : (hostId == "managedOverlay" ? "overlay" : (hostId == "mainMenu" ? "menu" : (hostId == "fixedTop" ? "header" : (hostId == "overwatchPanel" ? "panel" : null)))));
4212
4400
  this.setSectionBound(sectionBound);
4213
4401
  }
4214
4402
 
package/serviceWorker.js CHANGED
@@ -1,4 +1,4 @@
1
- const INSTALLATION_VERSION_NAME = "1.2.6-r20260422";
1
+ const INSTALLATION_VERSION_NAME = "1.4.0-r20260424";
2
2
  // ^^ Use for check new update "Native application(webview) version(or Android/iOS version combo) - PWA release version"
3
3
  // ex) "1.0.1/1.0.0-r20251101k"
4
4
 
@@ -10,6 +10,7 @@ const INSTALLATION_FILE_LIST = [
10
10
  "./staticDoc.html",
11
11
  "./instantDoc.html",
12
12
  "./managedOverlay.html",
13
+ "./overwatchPanel.html",
13
14
  "./customHandlePrototypes.html",
14
15
 
15
16
 
@@ -21,7 +22,7 @@ const INSTALLATION_FILE_LIST = [
21
22
 
22
23
 
23
24
  // Common files cache - Be changes some time but, well not changed very often
24
- const CACHE_NAME_COMMON_FILES = "common-files-cache-v1-20260422";
25
+ const CACHE_NAME_COMMON_FILES = "common-files-cache-v1-20260424";
25
26
 
26
27
  const COMMON_FILES_TO_CACHE = [
27
28
  "./",
@@ -50,6 +51,7 @@ const COMMON_FILES_TO_CACHE = [
50
51
  "./scripts/estreUi-core.js",
51
52
  "./scripts/estreUi-dialog.js",
52
53
  "./scripts/estreUi-notation.js",
54
+ "./scripts/estreUi-notification.js",
53
55
  "./scripts/estreUi-pageModel.js",
54
56
  "./scripts/estreUi-pageManager.js",
55
57
  "./scripts/estreUi-handles.js",
@@ -330,7 +330,7 @@ article .text_capsule.bordered { --border-color: var(--color-boundary); --bg-col
330
330
  article .text_capsule.hide_on_empty:empty { display: none; }
331
331
 
332
332
  article .h_icon_set { display: flex; flex-flow: row nowrap; align-items: stretch; }
333
- article .h_icon_set > .icon_place { width: fit-content; aspect-ratio: 1; flex-grow: 0; flex-shrink: 0; align-self: center; }
333
+ article .h_icon_set > .icon_place { width: fit-content; height: -webkit-fill-available; height: stretch; aspect-ratio: 1; flex-grow: 0; flex-shrink: 0; align-self: center; }
334
334
  article .h_icon_set > .icon_place > img { height: 100%; }
335
335
  article .h_icon_set > .icon_place > img[src=""] { width: 0; height: fit-content; }
336
336
  article .h_icon_set > .content_place { width: 100%; flex-grow: 1; flex-shrink: 1; }
@@ -124,8 +124,97 @@ nav#mainMenu[data-opened="1"] > section#grabArea div.pad { backdrop-filter: unse
124
124
  }
125
125
  }
126
126
 
127
+ /* overwatchPanel (drops from top) */
128
+ nav#overwatchPanel { --grab-y: 0px; --panel-block-height: calc(100vh - var(--top-pad) - 42px - var(--bottom-safe-pad)); position: fixed; z-index: 120; top: 0; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; pointer-events: none; user-select: none; }
129
+ nav#overwatchPanel > header#panelHeader,
130
+ nav#overwatchPanel > .dynamic_section_host,
131
+ nav#overwatchPanel > .dynamic_section_block,
132
+ nav#overwatchPanel > section#panelGrabArea { position: relative; pointer-events: auto; }
133
+ nav#overwatchPanel > header#panelHeader { z-index: 4; }
134
+ nav#overwatchPanel > .dynamic_section_host { z-index: 3; }
135
+ nav#overwatchPanel > .dynamic_section_block { z-index: 2; }
136
+ nav#overwatchPanel > section#panelGrabArea { z-index: 1; }
137
+ nav#overwatchPanel > header#panelHeader { display: flex; flex-direction: row; align-items: baseline; gap: 0.5em; padding: calc(var(--top-pad) + 4px) var(--basic-ui-inset-h) 4px; flex-shrink: 0; background-color: rgba(var(--cabr) / 60%); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); transform: translateY(-100%); transition-duration: 0.3s; }
138
+ nav#overwatchPanel > header#panelHeader > #panelClock { font-size: 1.125rem; font-weight: 600; }
139
+ nav#overwatchPanel > header#panelHeader > #panelDate { font-size: 0.875rem; opacity: 0.75; }
140
+ nav#overwatchPanel > .dynamic_section_host { display: flex; flex-flow: row nowrap; flex-shrink: 0; padding-inline: var(--basic-ui-inset-h); color: var(--color-text-lightest); background-color: rgba(var(--cabr) / 60%); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); transform: translateY(calc(-100% - var(--panel-block-height))); transition-duration: 0.3s; }
141
+ nav#overwatchPanel > .dynamic_section_host > .host_item { flex-grow: 1; padding: 8px 0 7px; border-bottom: solid 1px var(--color-boundary-o10); font-size: 1rem; font-weight: 500; text-align: center; line-height: 1.5em; cursor: pointer; transition-duration: 0.2s; }
142
+ nav#overwatchPanel > .dynamic_section_host > .host_item[data-showing="1"] { padding-bottom: 6px; border-bottom: solid 2px var(--color-indicator-bold); color: var(--color-text-darker); }
143
+ nav#overwatchPanel > .dynamic_section_block { display: flex; flex-flow: row nowrap; flex-shrink: 1; height: var(--panel-block-height); max-height: calc(100vh - var(--top-pad) - 42px - var(--bottom-safe-pad)); overflow-x: overlay; scrollbar-width: none; scroll-behavior: smooth; scroll-snap-type: x mandatory; background-color: rgba(var(--cabr) / 40%); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); transform: translateY(calc(-100vh - var(--panel-block-height))); transition-duration: 0.3s; }
144
+ nav#overwatchPanel > .dynamic_section_block > .block_item { width: 100%; flex-shrink: 0; overflow-y: auto; scroll-snap-align: start; }
145
+ nav#overwatchPanel > section#panelGrabArea { flex-grow: 0; flex-shrink: 0; height: 42px; background-color: transparent; opacity: 0; transition-duration: 0.3s; }
146
+ nav#overwatchPanel > section#panelGrabArea > div.handle { --width: 64px; --height: 4px; display: block; width: var(--width); height: var(--height); margin: 10px auto 0; border-radius: calc(var(--height) / 2); background-color: var(--color-boundary-lightside); }
147
+ nav#overwatchPanel > section#panelGrabArea > div.pad { flex-grow: 1; }
148
+
149
+ nav#overwatchPanel[data-opened="1"] > header#panelHeader,
150
+ nav#overwatchPanel[data-opened="1"] > .dynamic_section_host,
151
+ nav#overwatchPanel[data-opened="1"] > .dynamic_section_block { transform: translateY(0); }
152
+ nav#overwatchPanel[data-opened="1"] > section#panelGrabArea { opacity: 1; background-color: rgb(var(--cadm) / 20%); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px); }
153
+
154
+ nav#overwatchPanel[data-on-grab="1"] > header#panelHeader,
155
+ nav#overwatchPanel[data-on-grab="1"] > .dynamic_section_host,
156
+ nav#overwatchPanel[data-on-grab="1"] > .dynamic_section_block { transition-delay: 0s; transition-duration: 0s; }
157
+ nav#overwatchPanel[data-on-grab="1"]:not([data-opened="1"]) > header#panelHeader { transform: translateY(calc(-100% + min(max(var(--grab-y), 0px), 100%))); }
158
+ nav#overwatchPanel[data-on-grab="1"]:not([data-opened="1"]) > .dynamic_section_host { transform: translateY(calc(-100% - var(--panel-block-height) + min(max(var(--grab-y), 0px), calc(100% + var(--panel-block-height))))); }
159
+ nav#overwatchPanel[data-on-grab="1"]:not([data-opened="1"]) > .dynamic_section_block { transform: translateY(calc(-100vh - var(--panel-block-height) + min(max(var(--grab-y), 0px), calc(100vh + var(--panel-block-height))))); }
160
+ nav#overwatchPanel[data-opened="1"][data-on-grab="1"] > header#panelHeader,
161
+ nav#overwatchPanel[data-opened="1"][data-on-grab="1"] > .dynamic_section_host,
162
+ nav#overwatchPanel[data-opened="1"][data-on-grab="1"] > .dynamic_section_block { transform: translateY(min(var(--grab-y), 0px)); }
163
+
164
+ /* Tablet+ (≥740 wide) — surface both block_items side-by-side instead of tab swipe. */
165
+ @media all and (min-width: 740px) {
166
+ nav#overwatchPanel > .dynamic_section_host { display: none; }
167
+ nav#overwatchPanel > .dynamic_section_block { scroll-snap-type: none; overflow-x: hidden; }
168
+ nav#overwatchPanel > .dynamic_section_block > .block_item { width: auto; flex: 1 1 0; min-width: 0; }
169
+ }
170
+
171
+ /* Top swipe trigger strip. Sits above fixedTop (z-index 130) so the downward swipe can fire while the panel is closed.
172
+ Height stays inside the safe area (status bar / notch) plus a small 8px bleed into fixedTop so the strip
173
+ does not cover tappable fixedTop controls. */
174
+ section#panelTrigger { position: fixed; z-index: 135; top: 0; left: 0; right: 0; height: calc(var(--top-safe-pad) + 8px); user-select: none; pointer-events: auto; background-color: transparent; }
175
+ nav#overwatchPanel[data-opened="1"] ~ section#panelTrigger { pointer-events: none; }
176
+
177
+ /* Quick panel tiles */
178
+ .quick_tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); gap: 8px; padding: 8px var(--basic-ui-inset-h); }
179
+ .quick_tile { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: 12px 8px; border-radius: 12px; border: 1px solid rgb(var(--cadm) / 20%); background-color: rgba(var(--cabr) / 30%); cursor: pointer; user-select: none; }
180
+ .quick_tile > .tile_icon { font-size: 1.5rem; line-height: 1; }
181
+ .quick_tile > .tile_label { font-size: 0.75rem; }
182
+ #darkModeToggle[data-dark-mode-state="light"] { background-color: rgba(var(--cabr) / 50%); }
183
+ #darkModeToggle[data-dark-mode-state="dark"] { background-color: rgba(var(--cadm) / 50%); }
184
+
185
+ /* Timeline (overwatchPanel #timeline) — roadmap #010. Reuses .post_block visuals from estreUiCore2.css. */
186
+ nav#overwatchPanel #timeline { --bg-color: rgb(var(--cabr) / 70%); box-sizing: border-box; padding: 8px var(--basic-ui-inset-h) calc(8px + var(--bottom-safe-pad)); }
187
+ nav#overwatchPanel #timeline > .timeline_host { display: flex; flex-flow: column nowrap; gap: 10px; }
188
+ nav#overwatchPanel #timeline .timeline_group { display: flex; flex-flow: column nowrap; gap: 6px; }
189
+ nav#overwatchPanel #timeline .timeline_group_header { display: flex; align-items: center; justify-content: space-between; padding: 4px 4px 2px; font-size: 0.75rem; font-weight: 600; color: rgb(var(--ca) / 70%); letter-spacing: 0.02em; text-transform: uppercase; }
190
+ nav#overwatchPanel #timeline .timeline_group_header > .timeline_group_label { flex: 1 1 auto; min-width: 0; }
191
+ nav#overwatchPanel #timeline .timeline_clear_all { flex: 0 0 auto; margin-left: 8px; padding: 3px 10px; border: none; border-radius: 10px; background-color: rgb(var(--ca) / 10%); color: rgb(var(--ca) / 80%); font: inherit; letter-spacing: inherit; text-transform: inherit; cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; }
192
+ nav#overwatchPanel #timeline .timeline_clear_all:active { background-color: rgb(var(--ca) / 25%); }
193
+ nav#overwatchPanel #timeline .timeline_item { display: flex; align-items: center; gap: 10px; padding: 10px 14px; box-sizing: border-box; border-radius: 14px; background-color: var(--bg-color); backdrop-filter: var(--basic-backdrop-blur); -webkit-backdrop-filter: var(--basic-backdrop-blur); box-shadow: 1px 2px 4px 1px rgb(var(--ca) / 18%); cursor: pointer; user-select: none; }
194
+ nav#overwatchPanel #timeline .timeline_item > .icon_place { flex: 0 0 auto; width: 38px; height: 38px; border-radius: 8px; overflow: hidden; display: flex; align-items: center; justify-content: center; }
195
+ nav#overwatchPanel #timeline .timeline_item > .icon_place > img { width: 100%; height: 100%; object-fit: cover; }
196
+ nav#overwatchPanel #timeline .timeline_item > .content_place { flex: 1 1 auto; min-width: 0; --color: var(--color-text); --size: 0.9375rem; --weight: 400; }
197
+ nav#overwatchPanel #timeline .timeline_item > .content_place > .title_line { font-size: 0.9375rem; font-weight: 600; color: var(--color-text); line-height: 1.25em; }
198
+ nav#overwatchPanel #timeline .timeline_item > .content_place > .subtitle_line { font-size: 0.8125rem; font-weight: 400; color: rgb(var(--ca) / 70%); line-height: 1.25em; margin-top: 1px; }
199
+ nav#overwatchPanel #timeline .timeline_item > .content_place > .content_area { display: flex; gap: 8px; align-items: flex-start; margin-top: 3px; }
200
+ nav#overwatchPanel #timeline .timeline_item > .content_place > .content_area > .content_place { flex: 1 1 auto; min-width: 0; color: var(--color); font-size: var(--size); font-weight: var(--weight); line-height: 1.3em; word-break: break-word; }
201
+ nav#overwatchPanel #timeline .timeline_item > .content_place > .content_area > .icon_place { flex: 0 0 auto; width: 20px; height: 20px; border-radius: 4px; overflow: hidden; }
202
+ nav#overwatchPanel #timeline .timeline_item > .content_place > .content_area > .icon_place > img { width: 100%; height: 100%; object-fit: cover; }
203
+ nav#overwatchPanel #timeline .timeline_empty { padding: 32px 16px; text-align: center; font-size: 0.875rem; color: rgb(var(--ca) / 60%); }
204
+ nav#overwatchPanel #timeline .timeline_item.timeline_item_enter { animation: timeline-item-enter 0.4s cubic-bezier(0.2, 0.8, 0.2, 1) both; transform-origin: top center; }
205
+ @keyframes timeline-item-enter {
206
+ 0% { opacity: 0; transform: translateY(-14px) scale(0.96); }
207
+ 60% { opacity: 1; }
208
+ 100% { opacity: 1; transform: translateY(0) scale(1); }
209
+ }
210
+ nav#overwatchPanel #timeline .timeline_item.timeline_item_exit { animation: timeline-item-exit 0.3s ease-in both; animation-delay: var(--exit-delay, 0ms); pointer-events: none; }
211
+ @keyframes timeline-item-exit {
212
+ 0% { opacity: 1; transform: translateX(0); }
213
+ 100% { opacity: 0; transform: translateX(60px); }
214
+ }
215
+
127
216
  /* root tabs (bottom) */
128
- footer#fixedBottom { position: fixed; display: flex; flex-direction: row; flex-wrap: nowrap; z-index: 110; bottom: 0; left: 0; right: 0; height: var(--rootbar-height); margin: 0; padding-bottom: var(--bottom-safe-pad); justify-content: center; background-color: rgb(var(--cwht) / 66.666%); backdrop-filter: var(--basic-backdrop-blur); -webkit-backdrop-filter: var(--basic-backdrop-blur); justify-content: center; user-select: none; }
217
+ footer#fixedBottom { position: fixed; display: flex; flex-direction: row; flex-wrap: nowrap; z-index: 110; bottom: 0; left: 0; right: 0; height: var(--rootbar-height); margin: 0; padding-bottom: var(--bottom-safe-pad); justify-content: center; background-color: var(--color-boundary-foggy-o66); backdrop-filter: var(--basic-backdrop-blur); -webkit-backdrop-filter: var(--basic-backdrop-blur); justify-content: center; user-select: none; }
129
218
  footer#fixedBottom nav { position: relative; display: flex; flex-direction: row; flex-wrap: nowrap; height: var(--rootbar-height); flex-grow: 1; flex-shrink: 1; user-select: none; }
130
219
  footer#fixedBottom nav:not(#rootbar) { max-width: 0; }
131
220
  footer#fixedBottom nav:first-child { justify-content: flex-end; }
@@ -290,7 +290,31 @@ nav#managedOverlay > section#notification > div.container > article { position:
290
290
  nav#managedOverlay > section#notification > div.container > article:not(:is([data-on-top^="1"], [data-on-top^="0"])) { display: none; }
291
291
  nav#managedOverlay > section#notification > div.container > article:not([data-on-top="1"]) { opacity: 0; }
292
292
  nav#managedOverlay > section#notification > div.container[data-container-id="noti"] { top: var(--top-pad); }
293
- nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article { top: 32px; }
293
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article { top: 0; transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-duration: 0.45s; will-change: transform, opacity; }
294
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article[data-on-top="1"] { top: 12px; transform: translateY(0); }
295
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article[data-on-top="0"] { top: 12px; transform: translateY(calc(-100% - var(--top-pad) - 12px)); }
296
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block { display: flex; align-items: center; gap: 10px; padding: 10px 14px; max-width: calc(100vw - var(--left-pad) - var(--right-pad) - 16px); min-width: min(320px, calc(100vw - var(--left-pad) - var(--right-pad) - 16px)); box-sizing: border-box; border-radius: 18px; background-color: var(--bg-color); backdrop-filter: var(--basic-backdrop-blur); -webkit-backdrop-filter: var(--basic-backdrop-blur); box-shadow: 1px 4px 8px 2px rgb(var(--ca) / 25%); cursor: pointer; }
297
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block:not([data-interactive]) { cursor: default; }
298
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .icon_place { flex: 0 0 auto; width: 38px; height: 38px; border-radius: 8px; overflow: hidden; display: flex; align-items: center; justify-content: center; }
299
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .icon_place > img { width: 100%; height: 100%; object-fit: cover; }
300
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .content_place { flex: 1 1 auto; min-width: 0; --color: var(--color-text); --size: 0.9375rem; --weight: 400; }
301
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .content_place > .title_line { font-size: 0.9375rem; font-weight: 600; color: var(--color-text); line-height: 1.25em; }
302
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .content_place > .subtitle_line { font-size: 0.8125rem; font-weight: 400; color: rgb(var(--ca) / 70%); line-height: 1.25em; margin-top: 1px; }
303
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .content_place > .content_area { display: flex; gap: 8px; align-items: flex-start; margin-top: 3px; }
304
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .content_place > .content_area > .content_place { flex: 1 1 auto; min-width: 0; color: var(--color); font-size: var(--size); font-weight: var(--weight); line-height: 1.3em; word-break: break-word; }
305
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .content_place > .content_area > .icon_place { flex: 0 0 auto; width: 20px; height: 20px; border-radius: 4px; overflow: hidden; }
306
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block > .content_place > .content_area > .icon_place > img { width: 100%; height: 100%; object-fit: cover; }
307
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block { position: relative; z-index: 1; }
308
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block.banner_incoming { animation: banner-incoming 0.45s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; }
309
+ nav#managedOverlay > section#notification > div.container[data-container-id="noti"] > article > .post_block.banner_ghost_exit { z-index: 0; animation: banner-ghost-exit 0.45s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; pointer-events: none; }
310
+ @keyframes banner-incoming {
311
+ 0% { opacity: 0; transform: translateY(calc(-100% - var(--top-pad) - 12px)); }
312
+ 100% { opacity: 1; transform: translateY(0); }
313
+ }
314
+ @keyframes banner-ghost-exit {
315
+ 0% { opacity: 1; transform: translateY(0); }
316
+ 100% { opacity: 0; transform: translateY(calc(-100% - var(--top-pad) - 12px)); }
317
+ }
294
318
  nav#managedOverlay > section#notification > div.container[data-container-id="note"] { bottom: var(--bottom-pad); }
295
319
  nav#managedOverlay > section#notification > div.container[data-container-id="note"] > article { bottom: 0; }
296
320
  nav#managedOverlay > section#notification > div.container[data-container-id="note"] > article:is([data-on-top^="1"], [data-on-top="0"]) { }
@@ -55,7 +55,8 @@ body {
55
55
 
56
56
  color: var(--color-text);
57
57
 
58
- --common-bg-color: var(--color-grayscale-lightness);
58
+ /* Concrete hex literal: this stylesheet loads eagerly, before the lazy-loaded estreUiRoot.css defines --color-* tokens, so var(--color-*) here would resolve to the guaranteed-invalid value and background-color would fall back to transparent. Host projects that want a project-owned splash tone override --common-bg-color in their own non-lazy initialize stylesheet. */
59
+ --common-bg-color: #CCC;
59
60
  background-color: var(--common-bg-color);
60
61
 
61
62
  font-size: 16px;
@@ -64,6 +65,9 @@ body[data-dark-mode="1"] {
64
65
 
65
66
  /* adaptive color (dark) */
66
67
 
68
+ /* Dark-mode splash fallback. Only takes effect in sessions that opt into FOLM pre-paint coupling (see index.html); otherwise the dark attribute lands after first paint and the light value above is what the splash shows. */
69
+ --common-bg-color: #222;
70
+
67
71
  }
68
72
 
69
73
 
@@ -60,6 +60,7 @@ html {
60
60
 
61
61
 
62
62
  --color-black: #000; --cblk: 0 0 0;
63
+ --color-barely-black: #070707; --cbblk: 7 7 7;
63
64
  --color-pseudo-black: #111; --cpblk: 17 17 17;
64
65
  --color-almost-black: #171717; --cablk: 23 23 23;
65
66
  --color-grayscale-darkest: #222; --cgdt: 34 34 34;
@@ -79,8 +80,9 @@ html {
79
80
  --color-grayscale-lightly: #D9D9D9; --cgly: 217 217 217;
80
81
  --color-grayscale-lightside: #DDD; --cgld: 221 221 221;
81
82
  --color-grayscale-lightest: #E7E7E7; --cglt: 231 231 231;
82
- --color-alomst-white: #EEE; --cawht: 238 238 238;
83
+ --color-almost-white: #EEE; --cawht: 238 238 238;
83
84
  --color-pseudo-white: #F7F7F7; --cpwht: 247 247 247;
85
+ --color-barely-white: #FAFAFA; --cbwht: 250 250 250;
84
86
  --color-white: #FFF; --cwht: 255 255 255;
85
87
 
86
88
  --color-focused: #F46224; --cf: 244 98 36;
@@ -128,6 +130,7 @@ html {
128
130
  --color-important-day-gray: #F5BF7E; --cidg: 245 191 126;
129
131
 
130
132
  --color-boundary-dim: var(--color-black); --cbdm: var(--cblk);
133
+ --color-boundary-dimly: var(--color-barely-black); --cbdmly: var(--cbblk);
131
134
  --color-boundary-dimmy: var(--color-pseudo-black); --cbdmy: var(--cpblk);
132
135
  --color-boundary-deepdark: var(--color-almost-black); --cbdd: var(--cablk);
133
136
  --color-boundary-darkest: var(--color-grayscale-darkest); --cbdt: var(--cgdt);
@@ -147,8 +150,9 @@ html {
147
150
  --color-boundary-lightly: var(--color-grayscale-lightly); --cbly: var(--cgly);
148
151
  --color-boundary-lightside: var(--color-grayscale-lightside); --cbld: var(--cgld);
149
152
  --color-boundary-lightest: var(--color-grayscale-lightest); --cblt: var(--cglt);
150
- --color-boundary-highlight: var(--color-alomst-white); --cbhl: var(--cawht);
153
+ --color-boundary-highlight: var(--color-almost-white); --cbhl: var(--cawht);
151
154
  --color-boundary-brighty: var(--color-pseudo-white); --cbbry: var(--cpwht);
155
+ --color-boundary-brightly: var(--color-barely-white); --cbbrly: var(--cbwht);
152
156
  --color-boundary-bright: var(--color-white); --cbbr: var(--cwht);
153
157
 
154
158
  --color-boundary-o1: rgba(var(--cbdm) / 1%);
@@ -186,6 +190,7 @@ html {
186
190
  --color-boundary-foggy-o20: rgba(var(--cbbr) / 20%);
187
191
  --color-boundary-foggy-o25: rgba(var(--cbbr) / 25%);
188
192
  --color-boundary-foggy-o30: rgba(var(--cbbr) / 30%);
193
+ --color-boundary-foggy-o33: rgba(var(--cbbr) / 33.333%);
189
194
  --color-boundary-foggy-o35: rgba(var(--cbbr) / 35%);
190
195
  --color-boundary-foggy-o40: rgba(var(--cbbr) / 40%);
191
196
  --color-boundary-foggy-o45: rgba(var(--cbbr) / 45%);
@@ -193,6 +198,7 @@ html {
193
198
  --color-boundary-foggy-o55: rgba(var(--cbbr) / 55%);
194
199
  --color-boundary-foggy-o60: rgba(var(--cbbr) / 60%);
195
200
  --color-boundary-foggy-o65: rgba(var(--cbbr) / 65%);
201
+ --color-boundary-foggy-o66: rgba(var(--cbbr) / 66.666%);
196
202
  --color-boundary-foggy-o70: rgba(var(--cbbr) / 70%);
197
203
  --color-boundary-foggy-o75: rgba(var(--cbbr) / 75%);
198
204
  --color-boundary-foggy-o80: rgba(var(--cbbr) / 80%);
@@ -486,5 +492,136 @@ body {
486
492
  body[data-dark-mode="1"] {
487
493
 
488
494
  /* adaptive color (dark) */
495
+ /*
496
+ Baseline `--color-black` ~ `--color-grayscale-*` ~ `--color-white` palette
497
+ is intentionally inherited from light mode. Only the *semantic* color sets
498
+ below (text / boundary / point / adaptive) flip here.
499
+
500
+ Brand-singleton colors (`--color-focused`, `--color-emphasis*`,
501
+ holiday/sunday/saturday/today/selected-day/important-day) keep their
502
+ identity hue and are not overridden.
503
+
504
+ The boundary opacity ramps (`--color-boundary-o*`, `--color-boundary-foggy-o*`)
505
+ must be re-declared below: CSS custom-property `var()` substitution happens
506
+ eagerly at the declaring scope, so ramps declared only at `:root` bake in
507
+ the light-mode `--cbdm`/`--cbbr` values and do not follow the dark override.
508
+ */
509
+
510
+ --color-text-darker: #FFF; --ctdr: 255 255 255;
511
+ --color-text-darken: #EEE; --ctdn: 238 238 238;
512
+ --color-text-dark: #DDD; --ctd: 221 221 221;
513
+ --color-text: #CCC; --ct: 204 204 204;
514
+ --color-text-light: #BBB; --ctl: 187 187 187;
515
+ --color-text-lighten: #AAA; --ctln: 170 170 170;
516
+ --color-text-lighter: #999; --ctlr: 153 153 153;
517
+ --color-text-lightness: #888; --ctls: 136 136 136;
518
+ --color-text-lightest: #777; --ctlt: 119 119 119;
519
+ --color-text-pale: #666; --ctp: 102 102 102;
520
+ --color-text-palen: #555; --ctpn: 85 85 85;
521
+ --color-text-paler: #444; --ctpr: 68 68 68;
522
+ --color-text-paleness: #333; --ctps: 51 51 51;
523
+ --color-text-palest: #222; --ctpt: 34 34 34;
524
+ --color-text-faint: #111; --ctf: 17 17 17;
525
+ --color-text-inverse: #000; --cai: 0 0 0;
526
+ --color-anti-text: #000; --cat: 0 0 0;
527
+
528
+ --color-boundary-dim: var(--color-white); --cbdm: var(--cwht);
529
+ --color-boundary-dimly: var(--color-barely-white); --cbdmly: var(--cbwht);
530
+ --color-boundary-dimmy: var(--color-pseudo-white); --cbdmy: var(--cpwht);
531
+ --color-boundary-deepdark: var(--color-almost-white); --cbdd: var(--cawht);
532
+ --color-boundary-darkest: var(--color-grayscale-lightest); --cbdt: var(--cglt);
533
+ --color-boundary-darkside: var(--color-grayscale-lightside); --cbdd: var(--cgld);
534
+ --color-boundary-darkly: var(--color-grayscale-lightly); --cbdy: var(--cgly);
535
+ --color-boundary-darkness: var(--color-grayscale-lightness); --cbds: var(--cgls);
536
+ --color-boundary-darker: var(--color-grayscale-lighter); --cbdr: var(--cglr);
537
+ --color-boundary-darken: var(--color-grayscale-lighten); --cbdn: var(--cgln);
538
+ --color-boundary-darkish: var(--color-grayscale-lightish); --cbdh: var(--cglh);
539
+ --color-boundary-dark: var(--color-grayscale-light); --cbd: var(--cgl);
540
+ --color-boundary-light: var(--color-grayscale-dark); --cbl: var(--cgd);
541
+ --color-boundary-lightish: var(--color-grayscale-darkish); --cblh: var(--cgdh);
542
+ --color-boundary-lighten: var(--color-grayscale-darken); --cbln: var(--cgdn);
543
+ --color-boundary-lighter: var(--color-grayscale-darker); --cblr: var(--cgdr);
544
+ --color-boundary-lightness: var(--color-grayscale-darkness); --cbls: var(--cgds);
545
+ --color-boundary-lightly: var(--color-grayscale-darkly); --cbly: var(--cgdy);
546
+ --color-boundary-lightside: var(--color-grayscale-darkside); --cbld: var(--cgdd);
547
+ --color-boundary-lightest: var(--color-grayscale-darkest); --cblt: var(--cgdt);
548
+ --color-boundary-highlight: var(--color-almost-black); --cbhl: var(--cablk);
549
+ --color-boundary-brighty: var(--color-pseudo-black); --cbbry: var(--cpblk);
550
+ --color-boundary-brightly: var(--color-barely-black); --cbbrly: var(--cbblk);
551
+ --color-boundary-bright: var(--color-black); --cbbr: var(--cblk);
552
+
553
+ --color-boundary-o1: rgba(var(--cbdm) / 1%);
554
+ --color-boundary-o3: rgba(var(--cbdm) / 3%);
555
+ --color-boundary-o5: rgba(var(--cbdm) / 5%);
556
+ --color-boundary-o7: rgba(var(--cbdm) / 7%);
557
+ --color-boundary-o10: rgba(var(--cbdm) / 10%);
558
+ --color-boundary-o15: rgba(var(--cbdm) / 15%);
559
+ --color-boundary-o20: rgba(var(--cbdm) / 20%);
560
+ --color-boundary-o25: rgba(var(--cbdm) / 25%);
561
+ --color-boundary-o30: rgba(var(--cbdm) / 30%);
562
+ --color-boundary-o35: rgba(var(--cbdm) / 35%);
563
+ --color-boundary-o40: rgba(var(--cbdm) / 40%);
564
+ --color-boundary-o45: rgba(var(--cbdm) / 45%);
565
+ --color-boundary-o50: rgba(var(--cbdm) / 50%);
566
+ --color-boundary-o55: rgba(var(--cbdm) / 55%);
567
+ --color-boundary-o60: rgba(var(--cbdm) / 60%);
568
+ --color-boundary-o65: rgba(var(--cbdm) / 65%);
569
+ --color-boundary-o70: rgba(var(--cbdm) / 70%);
570
+ --color-boundary-o75: rgba(var(--cbdm) / 75%);
571
+ --color-boundary-o80: rgba(var(--cbdm) / 80%);
572
+ --color-boundary-o85: rgba(var(--cbdm) / 85%);
573
+ --color-boundary-o90: rgba(var(--cbdm) / 90%);
574
+ --color-boundary-o93: rgba(var(--cbdm) / 93%);
575
+ --color-boundary-o95: rgba(var(--cbdm) / 95%);
576
+ --color-boundary-o97: rgba(var(--cbdm) / 97%);
577
+ --color-boundary-o99: rgba(var(--cbdm) / 99%);
578
+
579
+ --color-boundary-foggy-o1: rgba(var(--cbbr) / 1%);
580
+ --color-boundary-foggy-o3: rgba(var(--cbbr) / 3%);
581
+ --color-boundary-foggy-o5: rgba(var(--cbbr) / 5%);
582
+ --color-boundary-foggy-o7: rgba(var(--cbbr) / 7%);
583
+ --color-boundary-foggy-o10: rgba(var(--cbbr) / 10%);
584
+ --color-boundary-foggy-o15: rgba(var(--cbbr) / 15%);
585
+ --color-boundary-foggy-o20: rgba(var(--cbbr) / 20%);
586
+ --color-boundary-foggy-o25: rgba(var(--cbbr) / 25%);
587
+ --color-boundary-foggy-o30: rgba(var(--cbbr) / 30%);
588
+ --color-boundary-foggy-o33: rgba(var(--cbbr) / 33.333%);
589
+ --color-boundary-foggy-o35: rgba(var(--cbbr) / 35%);
590
+ --color-boundary-foggy-o40: rgba(var(--cbbr) / 40%);
591
+ --color-boundary-foggy-o45: rgba(var(--cbbr) / 45%);
592
+ --color-boundary-foggy-o50: rgba(var(--cbbr) / 50%);
593
+ --color-boundary-foggy-o55: rgba(var(--cbbr) / 55%);
594
+ --color-boundary-foggy-o60: rgba(var(--cbbr) / 60%);
595
+ --color-boundary-foggy-o65: rgba(var(--cbbr) / 65%);
596
+ --color-boundary-foggy-o66: rgba(var(--cbbr) / 66.666%);
597
+ --color-boundary-foggy-o70: rgba(var(--cbbr) / 70%);
598
+ --color-boundary-foggy-o75: rgba(var(--cbbr) / 75%);
599
+ --color-boundary-foggy-o80: rgba(var(--cbbr) / 80%);
600
+ --color-boundary-foggy-o85: rgba(var(--cbbr) / 85%);
601
+ --color-boundary-foggy-o90: rgba(var(--cbbr) / 90%);
602
+ --color-boundary-foggy-o93: rgba(var(--cbbr) / 93%);
603
+ --color-boundary-foggy-o95: rgba(var(--cbbr) / 95%);
604
+ --color-boundary-foggy-o97: rgba(var(--cbbr) / 97%);
605
+ --color-boundary-foggy-o99: rgba(var(--cbbr) / 99%);
606
+
607
+ --color-point-dim: var(--color-white); --cpdm: var(--cwht);
608
+ --color-point-dark: var(--color-grayscale-lighter); --cpd: var(--cglr);
609
+ --color-point: var(--color-grayscale-dark); --cp: var(--cgd);
610
+ --color-point-light: var(--color-grayscale-darker); --cpl: var(--cgdr);
611
+ --color-point-bright: var(--color-black); --cpbr: var(--cblk);
612
+
613
+ --color-point-sub-dim: var(--color-white); --cpsdm: var(--cwht);
614
+ --color-point-sub-dark: var(--color-grayscale-lighter); --cpsd: var(--cglr);
615
+ --color-point-sub: var(--color-grayscale-dark); --cps: var(--cgd);
616
+ --color-point-sub-light: var(--color-grayscale-darker); --cpsl: var(--cgdr);
617
+ --color-point-sub-bright: var(--color-black); --cpsbr: var(--cblk);
618
+
619
+ --color-adaptive-dimmest: var(--color-white); --cadmt: var(--cwht);
620
+ --color-adaptive-dim: var(--color-pseudo-white); --cadm: var(--cpwht);
621
+ --color-adaptive-dark: var(--color-grayscale-lighter); --cad: var(--cglr);
622
+ --color-adaptive: var(--color-grayscale-darken); --ca: var(--cgdn);
623
+ --color-adaptive-light: var(--color-grayscale-darkness); --cal: var(--cgds);
624
+ --color-adaptive-bright: var(--color-pseudo-black); --cabr: var(--cpblk);
625
+ --color-adaptive-brightest: var(--color-black); --cabrt: var(--cblk);
489
626
 
490
627
  }