/* * Page skeletons (components/boot-skeleton). * * The server draws every variant of a skeleton; these variants show the one * that matches the attributes the boot script set on before the first * paint (lib/boot-skeleton/boot-script.ts). Part of the first stylesheet, so * nothing here arrives late. */ /* Mountain View shell. Its geometry only applies on desktop, so pair it with lg: in markup (lg:mv:hidden), except the phone bottom bar, which follows the layout at every width. */ @custom-variant mv (&:where([data-interface-layout="mountain-view"] *)); /* Mail layout (effectiveMailLayout: Mountain View and simple mode are focus). */ @custom-variant boot-split (&:where([data-boot-mail-layout="split"] *)); @custom-variant boot-horizontal (&:where([data-boot-mail-layout="horizontal"] *)); @custom-variant boot-focus (&:where([data-boot-mail-layout="focus"] *)); /* A message, thread, contact, settings page or admin page is open. */ @custom-variant boot-open (&:where([data-boot-pane] *)); @custom-variant boot-thread (&:where([data-boot-pane="thread"] *)); /* The Pro interface takes this page over on a desktop. */ @custom-variant boot-pro (&:where([data-boot-pro="on"] *)); /* Nothing stored that checkAuth could restore: draw the login card. */ @custom-variant boot-out (&:where([data-boot-auth="out"] *)); /* Calendar view. */ @custom-variant boot-cal-month (&:where([data-boot-calendar-view="month"] *)); @custom-variant boot-cal-week (&:where([data-boot-calendar-view="week"] *)); @custom-variant boot-cal-day (&:where([data-boot-calendar-view="day"] *)); @custom-variant boot-cal-agenda (&:where([data-boot-calendar-view="agenda"] *)); @custom-variant boot-cal-tasks (&:where([data-boot-calendar-view="tasks"] *)); @custom-variant boot-cal-collapsed (&:where([data-boot-collapsed~="calendar"] *)); /* Files. */ @custom-variant boot-files-grid (&:where([data-boot-files-view="grid"] *)); @custom-variant boot-files-details (&:where([data-boot-files-details="on"] *)); /* What the rail showed last time (bulwark-boot-hints). Without hints every app is drawn: the rail of a server with all of them. */ @custom-variant boot-no-calendar (&:where([data-boot-rail]:not([data-boot-rail~="calendar"]) *)); @custom-variant boot-no-contacts (&:where([data-boot-rail]:not([data-boot-rail~="contacts"]) *)); @custom-variant boot-no-files (&:where([data-boot-rail]:not([data-boot-rail~="files"]) *)); @custom-variant boot-rail-add-app (&:where([data-boot-rail~="add-app"] *)); @custom-variant boot-rail-admin (&:where([data-boot-rail~="admin"] *)); @custom-variant boot-rail-a11y (&:where([data-boot-rail~="a11y"] *)); @custom-variant boot-rail-quota (&:where([data-boot-rail~="quota"] *)); /* A placeholder shape. A slow opacity pulse rather than a moving shimmer: opacity runs on the compositor, so the skeleton costs the main thread nothing while the app's JS is still starting up. */ .sk-shape { background-color: var(--color-muted); animation: sk-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } @keyframes sk-pulse { 50% { opacity: 0.55; } } /* Reduced motion: no pulse at all (the global rule only shortens it). */ @media (prefers-reduced-motion: reduce) { :root:not([data-motion="full"]) .sk-shape { animation: none; } } :root[data-motion="reduce"] .sk-shape { animation: none; } /* More contrast: shapes that stand out from the panels they sit on. */ @media (prefers-contrast: more) { :root:not([data-contrast="normal"]) .sk-shape { background-color: color-mix(in oklab, var(--color-foreground) 28%, transparent); } } :root[data-contrast="more"] .sk-shape { background-color: color-mix(in oklab, var(--color-foreground) 28%, transparent); } /* Forced colours drop backgrounds; keep the shapes as system grey. */ @media (forced-colors: active) { .sk-shape { forced-color-adjust: none; background-color: GrayText; animation: none; } } /* pro */ /* The Pro shell takes a standard page over (components/boot-skeleton/shell.tsx): on a desktop with the Pro interface on, unless the visitor is signed out, and never again inside the Pro shell itself (an embedded page's gate). */ @custom-variant boot-pro-frame (&:where([data-boot-pro="on"]:not([data-boot-auth="out"]) *):not(:where([data-pro-shell] *))); /* The Pro split pane, on its stored side. */ @custom-variant boot-pro-split (&:where([data-boot-pro-split] *)); @custom-variant boot-pro-split-left (&:where([data-boot-pro-split="left"] *)); /* Each pane's tab strip draws as many tabs as the store holds (up to eight), and its body the active tab's page (lib/boot-skeleton/boot-script.ts, data-boot-pro--tabs / -active / -kind). One tab and mail without them. */ [data-sk-pro-tab]:nth-child(n+2), [data-sk-pro-body] { display: none; } :root[data-boot-pro-main-tabs="2"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(-n+2), :root[data-boot-pro-main-tabs="3"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(-n+3), :root[data-boot-pro-main-tabs="4"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(-n+4), :root[data-boot-pro-main-tabs="5"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(-n+5), :root[data-boot-pro-main-tabs="6"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(-n+6), :root[data-boot-pro-main-tabs="7"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(-n+7), :root[data-boot-pro-main-tabs="8"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(-n+8), :root[data-boot-pro-split-tabs="2"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(-n+2), :root[data-boot-pro-split-tabs="3"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(-n+3), :root[data-boot-pro-split-tabs="4"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(-n+4), :root[data-boot-pro-split-tabs="5"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(-n+5), :root[data-boot-pro-split-tabs="6"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(-n+6), :root[data-boot-pro-split-tabs="7"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(-n+7), :root[data-boot-pro-split-tabs="8"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(-n+8) { display: flex; } :root:not([data-boot-pro-main-active]) [data-sk-pro-pane="main"] [data-sk-pro-tab]:first-child, :root:not([data-boot-pro-split-active]) [data-sk-pro-pane="split"] [data-sk-pro-tab]:first-child, :root[data-boot-pro-main-active="0"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(1), :root[data-boot-pro-main-active="1"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(2), :root[data-boot-pro-main-active="2"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(3), :root[data-boot-pro-main-active="3"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(4), :root[data-boot-pro-main-active="4"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(5), :root[data-boot-pro-main-active="5"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(6), :root[data-boot-pro-main-active="6"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(7), :root[data-boot-pro-main-active="7"] [data-sk-pro-pane="main"] [data-sk-pro-tab]:nth-child(8), :root[data-boot-pro-split-active="0"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(1), :root[data-boot-pro-split-active="1"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(2), :root[data-boot-pro-split-active="2"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(3), :root[data-boot-pro-split-active="3"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(4), :root[data-boot-pro-split-active="4"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(5), :root[data-boot-pro-split-active="5"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(6), :root[data-boot-pro-split-active="6"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(7), :root[data-boot-pro-split-active="7"] [data-sk-pro-pane="split"] [data-sk-pro-tab]:nth-child(8) { /* ProTabBar's active tab; its bottom edge covers the strip's border. */ background-color: var(--color-background); border-inline-color: rgba(128, 128, 128, 0.3); --sk-pro-tab-accent: var(--sk-pro-pane-accent); } :root:not([data-boot-pro-focus="split"]) [data-sk-pro-pane="main"], :root[data-boot-pro-focus="split"] [data-sk-pro-pane="split"] { /* The focused pane's active tab carries the accent top edge. */ --sk-pro-pane-accent: var(--color-primary); } :root:not([data-boot-pro-main-kind]) [data-sk-pro-pane="main"] [data-sk-pro-body="mail"], :root:not([data-boot-pro-split-kind]) [data-sk-pro-pane="split"] [data-sk-pro-body="mail"], :root[data-boot-pro-main-kind="mail"] [data-sk-pro-pane="main"] [data-sk-pro-body="mail"], :root[data-boot-pro-main-kind="calendar"] [data-sk-pro-pane="main"] [data-sk-pro-body="calendar"], :root[data-boot-pro-main-kind="contacts"] [data-sk-pro-pane="main"] [data-sk-pro-body="contacts"], :root[data-boot-pro-main-kind="files"] [data-sk-pro-pane="main"] [data-sk-pro-body="files"], :root[data-boot-pro-main-kind="settings"] [data-sk-pro-pane="main"] [data-sk-pro-body="settings"], :root[data-boot-pro-main-kind="other"] [data-sk-pro-pane="main"] [data-sk-pro-body="other"], :root[data-boot-pro-split-kind="mail"] [data-sk-pro-pane="split"] [data-sk-pro-body="mail"], :root[data-boot-pro-split-kind="calendar"] [data-sk-pro-pane="split"] [data-sk-pro-body="calendar"], :root[data-boot-pro-split-kind="contacts"] [data-sk-pro-pane="split"] [data-sk-pro-body="contacts"], :root[data-boot-pro-split-kind="files"] [data-sk-pro-pane="split"] [data-sk-pro-body="files"], :root[data-boot-pro-split-kind="settings"] [data-sk-pro-pane="split"] [data-sk-pro-body="settings"], :root[data-boot-pro-split-kind="other"] [data-sk-pro-pane="split"] [data-sk-pro-body="other"] { display: block; } /* The rail marks the focused tab's app (pro/page.tsx, railActiveItemId). */ :root:not([data-boot-pro-kind]) [data-pro-shell] [data-sk-rail="mail"], :root[data-boot-pro-kind="mail"] [data-pro-shell] [data-sk-rail="mail"], :root[data-boot-pro-kind="calendar"] [data-pro-shell] [data-sk-rail="calendar"], :root[data-boot-pro-kind="contacts"] [data-pro-shell] [data-sk-rail="contacts"], :root[data-boot-pro-kind="files"] [data-pro-shell] [data-sk-rail="files"], :root[data-boot-pro-kind="settings"] [data-pro-shell] [data-sk-rail="settings"] { background-color: color-mix(in oklab, var(--color-primary) 10%, transparent); color: var(--color-primary); }