teqo-backup/src/components/campaign/activity/ActivityAgenda.css

396 lines
11 KiB
CSS

.activity-agenda-shell {
overflow: hidden;
border: 1px solid var(--border);
border-radius: 0.75rem;
background: var(--card);
box-shadow: 0 4px 24px rgb(28 25 23 / 8%);
}
.activity-agenda {
--fc-classic-button: var(--secondary);
--fc-classic-button-border: var(--border);
--fc-classic-button-strong: var(--primary);
--fc-classic-button-strong-border: var(--primary);
--fc-classic-button-outline: color-mix(in oklab, var(--ring) 55%, transparent);
--fc-classic-button-foreground: var(--secondary-foreground);
--fc-classic-primary: var(--primary);
--fc-classic-primary-foreground: var(--primary-foreground);
--fc-classic-event: var(--primary);
--fc-classic-event-contrast: var(--primary-foreground);
--fc-classic-background-event: var(--support-engaged);
--fc-classic-background-event-opacity: 18%;
--fc-classic-background-event-foreground-opacity: 60%;
--fc-classic-highlight: color-mix(in oklab, var(--primary) 9%, transparent);
--fc-classic-today: color-mix(in oklab, var(--scope) 72%, transparent);
--fc-classic-now: var(--primary);
--fc-classic-small-dot-width: 8px;
--fc-classic-large-dot-width: 10px;
--fc-classic-background: var(--background);
--fc-classic-faint: color-mix(in oklab, var(--foreground) 3%, transparent);
--fc-classic-muted: color-mix(in oklab, var(--foreground) 8%, transparent);
--fc-classic-strong: color-mix(in oklab, var(--foreground) 14%, transparent);
--fc-classic-foreground: var(--foreground);
--fc-classic-faint-foreground: var(--muted-foreground);
--fc-classic-muted-foreground: var(--muted-foreground);
--fc-classic-border: var(--border);
--fc-classic-strong-border: var(--input);
padding: 1rem;
font-size: 0.875rem;
/* C101 — the horizontal swipe (navigation) must see pointermove events:
without a touch-action the browser claims any touch drag for panning and
fires pointercancel at the first move, killing the gesture before the
threshold. pan-y keeps vertical scrolling native while horizontal
movements stay with the page. FullCalendar's own drags survive: during an
event drag it preventDefaults window touchmoves (its touchScrollAllowed
cancellation), which stops the browser's pan claim. */
touch-action: pan-y;
/* C110 — the adjacent-period preview is positioned against the grid's own
edge (left:100% / right:100% of this container), which only works with a
containing block here. */
position: relative;
}
/* C110 — the live drag: the grid is directly manipulated by the finger (the
transform is imperative, written by the swipe hook — no React state at
60fps) and the release settles it with a short exit slide (commit) or the
snap-back. */
.activity-agenda.activity-agenda-swipe-dragging {
will-change: transform;
}
.activity-agenda.activity-agenda-swipe-exit {
transition: transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* C110 — the adjacent-period reveal: a child of the transformed grid
container, glued to the seam. It rides the same transform as the grid (it
is a child), so the strip that opens at the grid's leading edge shows the
preview's seam edge — no dx bookkeeping in JS. */
.activity-agenda-swipe-preview {
position: absolute;
inset-block: 0;
width: 100%;
pointer-events: none;
overflow: hidden;
background: var(--card);
}
.activity-agenda-swipe-preview--next {
left: 100%;
border-left: 1px solid var(--border);
}
.activity-agenda-swipe-preview--prev {
right: 100%;
border-right: 1px solid var(--border);
}
.activity-agenda-swipe-preview-content {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
gap: 0.375rem;
padding: 0.625rem;
}
.activity-agenda-swipe-preview--prev .activity-agenda-swipe-preview-content {
align-items: flex-end;
text-align: right;
}
.activity-agenda-swipe-chevron {
width: 1.25rem;
height: 1.25rem;
color: var(--muted-foreground);
}
.activity-agenda-swipe-label {
font-size: 0.6875rem;
font-weight: 600;
line-height: 1.2;
color: var(--muted-foreground);
white-space: nowrap;
}
/* The abstract grid frame ("quadro do grid"): a week/day header plus faint
column/time bands. Not a second FullCalendar — deliberately a skeleton. */
.activity-agenda-swipe-frame {
width: 100%;
flex: 1;
border: 1px solid var(--border);
border-radius: 0.375rem;
overflow: hidden;
opacity: 0.55;
background-image: repeating-linear-gradient(
to right,
transparent 0,
transparent calc(14.285% - 1px),
var(--border) calc(14.285% - 1px),
var(--border) 14.285%
);
}
.activity-agenda-swipe-frame[data-view='day'] {
background-image: repeating-linear-gradient(
to bottom,
transparent 0,
transparent calc(20% - 1px),
var(--border) calc(20% - 1px),
var(--border) 20%
);
}
.activity-agenda-swipe-frame[data-view='month'] {
background-image:
repeating-linear-gradient(
to right,
transparent 0,
transparent calc(14.285% - 1px),
var(--border) calc(14.285% - 1px),
var(--border) 14.285%
),
repeating-linear-gradient(
to bottom,
transparent 0,
transparent calc(16.66% - 1px),
var(--border) calc(16.66% - 1px),
var(--border) 16.66%
);
}
.activity-agenda-swipe-frame-head {
display: flex;
border-bottom: 1px solid var(--border);
}
.activity-agenda-swipe-frame-head span {
flex: 1;
padding: 0.1875rem 0;
text-align: center;
font-size: 0.5625rem;
font-weight: 600;
color: var(--muted-foreground);
}
.activity-agenda-swipe-frame-head span + span {
border-left: 1px solid var(--border);
}
/* C110 — the adjacent period's events enter the preview as they load (the
accept's async path): bars by time proportion for day/week, dots per date
for month, rows for the list. Approximate on purpose — the commit renders
the real grid. */
.activity-agenda-swipe-event,
.activity-agenda-swipe-dot {
position: absolute;
border-radius: 0.1875rem;
background: color-mix(in oklab, var(--primary) 72%, transparent);
}
.activity-agenda-swipe-event {
left: 0;
width: 62%;
height: 0.3125rem;
}
.activity-agenda-swipe-dot {
width: 9%;
height: 0.375rem;
}
.activity-agenda-swipe-list-row {
display: block;
width: 100%;
overflow: hidden;
padding: 0.3125rem 0.375rem;
border-radius: 0.25rem;
background: color-mix(in oklab, var(--foreground) 7%, transparent);
font-size: 0.625rem;
font-weight: 500;
text-overflow: ellipsis;
white-space: nowrap;
}
.activity-agenda button {
min-height: 2.75rem;
min-width: 2.75rem;
border-radius: var(--radius);
font-weight: 500;
}
.activity-agenda h2 {
font-size: 1.125rem;
font-weight: 600;
letter-spacing: -0.02em;
}
.activity-agenda-notice {
display: flex;
min-height: 4rem;
align-items: center;
justify-content: space-between;
gap: 1rem;
border-bottom: 1px solid var(--border);
background: var(--muted);
padding: 0.75rem 1rem;
color: var(--muted-foreground);
font-size: 0.875rem;
}
.activity-agenda-event-content {
display: grid;
min-width: 0;
gap: 0.125rem;
padding: 0.125rem 0.25rem;
line-height: 1.2;
}
.activity-agenda-event-heading {
display: flex;
min-width: 0;
align-items: center;
justify-content: space-between;
gap: 0.25rem;
}
.activity-agenda-event-time,
.activity-agenda-event-location,
.activity-agenda-event-tags {
overflow: hidden;
font-size: 0.6875rem;
opacity: 0.82;
text-overflow: ellipsis;
white-space: nowrap;
}
.activity-agenda-event-title {
overflow: hidden;
font-size: 0.75rem;
font-weight: 600;
text-overflow: ellipsis;
white-space: nowrap;
}
.activity-agenda-event-status {
font-size: 0.625rem;
font-weight: 600;
letter-spacing: 0.04em;
opacity: 0.85;
text-transform: uppercase;
}
.activity-agenda-deputy {
display: inline-flex;
flex: none;
align-items: center;
}
.activity-agenda-deputy svg {
width: 0.875rem;
height: 0.875rem;
}
.activity-agenda-event--cancelado .activity-agenda-event-title {
text-decoration: line-through;
}
/* C101 — the agenda's filter strip. The wrapper class lives in
ActivityAgendaFilters (agenda-only); the shared omnibox keeps its desktop
look everywhere else. Mobile: edge-to-edge, label visually hidden (still
the combobox's accessible name), sticky under the app top bar and flush
against the calendar card.
Sticky geometry: the wrapper's containing block must start flush under the
app bar, otherwise the sticky clamp pins it 1rem lower. The app scroll
container's top padding is therefore zeroed on the agenda page (scoped via
`:has`), so the page shell — and with it the strip's containing block —
starts at the top bar's bottom edge. */
.activity-agenda-filter-strip {
min-width: 0;
}
@media (max-width: 767px) {
[data-slot='campaign-content-scroll']:has(.activity-agenda-filter-strip) {
padding-top: 0;
}
.activity-agenda-filter-strip {
position: sticky;
top: 0;
z-index: 20;
margin-inline: -1rem;
margin-bottom: -1.5rem;
background: var(--background);
}
.activity-agenda-filter-strip label {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
}
@media (max-width: 767px) {
.activity-agenda-shell {
/* Edge-to-edge on phones: break out of the p-4 scroll padding and drop
the card side chrome so the calendar bleeds to the screen edges. */
margin-inline: -1rem;
border-inline: 0;
border-radius: 0;
}
.activity-agenda {
/* C101 — the day/week/month grid becomes a self-contained scroller on
phones (FullCalendar `height="100%"`), so the day header stays fixed
while the hours scroll and `scrollTime`/`scrollToTime` can anchor the
current hour. Budget: top bar + strip + bottom nav + page padding. */
height: calc(100svh - 12rem);
padding: 0.5rem 0;
font-size: 0.75rem;
}
/* C101-ux — the calendar container is a keyboard region on phones (it takes
tabIndex because the toolbar is hidden): a visible focus indication is
required. The ring stays INSIDE the card (negative offset) because the
edge-to-edge shell clips with `overflow: hidden` — a positive-offset
ring would be cut at the screen edge. */
.activity-agenda:focus-visible {
outline: 2px solid var(--ring);
outline-offset: -2px;
}
.activity-agenda h2 {
font-size: 0.9375rem;
}
.activity-agenda button {
padding-inline: 0.625rem;
}
.activity-agenda-notice {
align-items: stretch;
flex-direction: column;
}
.activity-agenda-event-location,
.activity-agenda-event-tags {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.activity-agenda,
.activity-agenda *,
.activity-agenda *::before,
.activity-agenda *::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
}
}