@cahyo-dimas/freeday 1.20.0 → 1.22.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.
- package/CHANGELOG.md +133 -0
- package/COMPONENTS.md +91 -2
- package/README.id.md +25 -1
- package/README.md +24 -1
- package/USAGE.md +42 -0
- package/dist/freeday.bundle.css +96 -10
- package/dist/freeday.css +85 -8
- package/dist/freeday.tokens.css +11 -2
- package/docs/agent-onboarding.md +39 -6
- package/docs/getting-started.md +15 -8
- package/package.json +2 -2
- package/src/base.css +15 -0
- package/src/components/accordion.css +5 -1
- package/src/components/app-shell.css +9 -0
- package/src/components/appbar.css +9 -0
- package/src/components/button.css +14 -0
- package/src/components/card.css +7 -1
- package/src/components/carousel.css +4 -1
- package/src/components/list.css +8 -1
- package/src/components/table.css +5 -2
- package/src/components/tabs.css +9 -2
package/src/base.css
CHANGED
|
@@ -14,6 +14,21 @@ h1, h2, h3, h4 { font-family: var(--font-display); font-weight: var(--weight-bol
|
|
|
14
14
|
a { color: var(--color-primary); }
|
|
15
15
|
:focus-visible { outline: var(--focus-ring-width) solid var(--focus-ring); outline-offset: var(--focus-ring-width); border-radius: var(--radius-xs); }
|
|
16
16
|
:where(button, input, select, textarea) { font: inherit; }
|
|
17
|
+
/* Hidden from sight, kept for assistive tech. `clip` hides PAINTING, not LAYOUT: the box still
|
|
18
|
+
* has a position, and because it is position:absolute its containing block is the nearest
|
|
19
|
+
* POSITIONED ancestor — with none, the initial containing block (the document itself).
|
|
20
|
+
*
|
|
21
|
+
* That matters, because `overflow` only clips a descendant whose containing block is inside the
|
|
22
|
+
* overflow box. So a hidden span in a horizontally scrolling table (the kit's own recommended way
|
|
23
|
+
* to name an icon button) parks at its static position — possibly thousands of px to the right —
|
|
24
|
+
* and drags the whole DOCUMENT sideways: invisible, and immune to `overflow-x:hidden` on every
|
|
25
|
+
* wrapper. Measured before the fix: 1351px of phantom page scroll from 11 spans.
|
|
26
|
+
*
|
|
27
|
+
* The fix is not here — it is on the containers: every clipping/scrolling container in the kit
|
|
28
|
+
* that holds consumer markup declares `position:relative` so it becomes the containing block for
|
|
29
|
+
* its own out-of-flow content (see test/css.test.mjs, which will not let a new one skip it).
|
|
30
|
+
* Note the measurement trap: documentElement.scrollWidth sees it, body.scrollWidth does not —
|
|
31
|
+
* the honest check is `window.scrollTo(9999, 0)` then reading `window.scrollX`. */
|
|
17
32
|
.fdy-visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
18
33
|
/* Opt-in list reset. base.css is intentionally a *light* reset — it does NOT strip list/paragraph
|
|
19
34
|
* margins (see the kit's own list components, which each reset themselves). If you run a utility
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/* Freeday — Accordion (native <details>/<summary>, zero-JS) */
|
|
2
|
-
|
|
2
|
+
/* position:relative — containing block for out-of-flow panel content (see base.css). NOT redundant
|
|
3
|
+
with the panel's reveal animation: that animation gives the panel a transform (which happens to
|
|
4
|
+
make it a containing block too), but it lives behind prefers-reduced-motion:no-preference — so
|
|
5
|
+
without this line the escape bug appears ONLY for readers who asked for reduced motion. */
|
|
6
|
+
.fdy-accordion{position:relative;border:var(--bw) solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;background:var(--color-surface);}
|
|
3
7
|
.fdy-accordion__item + .fdy-accordion__item{border-top:var(--bw) solid var(--color-border);}
|
|
4
8
|
.fdy-accordion__item > summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:var(--space-3);padding:var(--space-3) var(--space-4);font-weight:var(--weight-medium);color:var(--color-text);}
|
|
5
9
|
.fdy-accordion__item > summary::-webkit-details-marker{display:none;}
|
|
@@ -24,6 +24,15 @@
|
|
|
24
24
|
.fdy-app__brand-title{display:block;font-family:var(--font-display);font-weight:var(--weight-bold);font-size:var(--text-lg);color:var(--color-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
25
25
|
.fdy-app__brand-subtitle{display:block;font-size:var(--text-xs);font-weight:var(--weight-regular);color:var(--color-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
|
26
26
|
.fdy-nav{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:2px;padding:var(--space-3) var(--space-3) var(--space-6);}
|
|
27
|
+
/* Horizontal variant — the SAME nav links laid out as a row, for a top-nav application (one that
|
|
28
|
+
* puts its primary navigation in `.fdy-appbar` / `.fdy-app__topbar` and has no sidebar). Deliberately
|
|
29
|
+
* a modifier and not a new block: the item, its states and `aria-current="page"` are unchanged. That
|
|
30
|
+
* is the point — a navigation link is a link marked `aria-current`, never `aria-selected` (invalid
|
|
31
|
+
* ARIA on an anchor) and never a tab role, so borrowing `.fdy-tabs` for routes half-adopts a contract
|
|
32
|
+
* (roving tabindex, a panel per tab) that route links do not honour. position:relative because the
|
|
33
|
+
* row scrolls; see base.css on why a scroller must be a containing block. */
|
|
34
|
+
.fdy-nav--horizontal{position:relative;flex:0 1 auto;flex-direction:row;align-items:center;gap:var(--space-1);padding:0;min-height:0;overflow-x:auto;}
|
|
35
|
+
.fdy-nav--horizontal .fdy-nav__item{white-space:nowrap;}
|
|
27
36
|
.fdy-nav__item{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text-muted);text-decoration:none;cursor:pointer;transition:background var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard);}
|
|
28
37
|
.fdy-nav__item:hover{background:var(--color-surface-2);color:var(--color-text);}
|
|
29
38
|
/* Active indicator stays in the primary ramp so it never clashes with a re-themed accent. */
|
|
@@ -10,6 +10,15 @@
|
|
|
10
10
|
.fdy-appbar__brand svg{display:block;width:1.5rem;height:1.5rem;}
|
|
11
11
|
.fdy-appbar__spacer{flex:1;}
|
|
12
12
|
.fdy-appbar__actions{display:inline-flex;align-items:center;gap:var(--space-1);}
|
|
13
|
+
/* Primary navigation inside the bar: `<nav class="fdy-nav fdy-nav--horizontal">` with
|
|
14
|
+
`.fdy-nav__item` links (see app-shell.css). The bar ships no link class of its own — a nav link
|
|
15
|
+
is the same component whether the nav is a sidebar column or a top row. */
|
|
13
16
|
/* Controls on a coloured app bar go on-colour (icons stay legible, hover is a light wash) */
|
|
14
17
|
.fdy-appbar--primary .fdy-btn--ghost{background:transparent;border-color:transparent;color:var(--color-on-primary);box-shadow:none;}
|
|
15
18
|
.fdy-appbar--primary .fdy-btn--ghost:hover{background:color-mix(in srgb,var(--color-on-primary) 16%,transparent);color:var(--color-on-primary);transform:none;}
|
|
19
|
+
/* Nav links on a coloured bar: full on-colour ink in every state (a dimmed variant would trade away
|
|
20
|
+
the contrast the bar's own token pair guarantees). The current page is carried by the background
|
|
21
|
+
wash plus the semibold weight the base rule already applies — and by `aria-current` itself. */
|
|
22
|
+
.fdy-appbar--primary .fdy-nav__item{color:var(--color-on-primary);}
|
|
23
|
+
.fdy-appbar--primary .fdy-nav__item:hover{background:color-mix(in srgb,var(--color-on-primary) 16%,transparent);color:var(--color-on-primary);}
|
|
24
|
+
.fdy-appbar--primary .fdy-nav__item[aria-current="page"]{background:color-mix(in srgb,var(--color-on-primary) 24%,transparent);color:var(--color-on-primary);}
|
|
@@ -10,6 +10,14 @@
|
|
|
10
10
|
.fdy-btn:hover{transform:translateY(-1px);box-shadow:0 6px 18px -2px color-mix(in srgb,var(--color-primary) 60%,transparent),inset 0 1px 0 rgba(255,255,255,.26);}
|
|
11
11
|
.fdy-btn:active{transform:translateY(1px);box-shadow:0 1px 4px -1px color-mix(in srgb,var(--color-primary) 46%,transparent);}
|
|
12
12
|
.fdy-btn:disabled{opacity:.5;cursor:not-allowed;transform:none;box-shadow:none;}
|
|
13
|
+
/* Pressed / toggle. `aria-pressed` is already the right attribute for a toggle button, so this adds
|
|
14
|
+
no class and no new markup contract — and it is what makes .fdy-btn-group a complete segmented
|
|
15
|
+
control: the group joins the borders, this says which segment you are on. Each fill variant
|
|
16
|
+
defines its OWN pressed look below; a single shared rule cannot work, because a gradient is a
|
|
17
|
+
background-IMAGE and would blank the ghost variant's background-color. Solid: invert the gradient
|
|
18
|
+
and sink the shadow inward, so a held button reads as depressed, not merely primary-coloured. */
|
|
19
|
+
.fdy-btn[aria-pressed="true"]{background:linear-gradient(180deg,color-mix(in srgb,#000 12%,var(--color-primary)),var(--color-primary));box-shadow:inset 0 2px 6px color-mix(in srgb,#000 22%,transparent);}
|
|
20
|
+
.fdy-btn[aria-pressed="true"]:hover{transform:none;box-shadow:inset 0 2px 6px color-mix(in srgb,#000 22%,transparent);}
|
|
13
21
|
|
|
14
22
|
.fdy-btn--ghost{background:var(--color-surface);color:var(--color-primary-strong);border-color:var(--color-border-strong);box-shadow:var(--shadow-1);}
|
|
15
23
|
.fdy-btn--ghost:hover{transform:none;background:var(--color-primary-soft);border-color:var(--color-primary-border);box-shadow:var(--shadow-1);}
|
|
@@ -18,6 +26,7 @@
|
|
|
18
26
|
.fdy-btn--danger{background:linear-gradient(180deg,var(--color-danger-btn),color-mix(in srgb,#000 12%,var(--color-danger-btn)));color:var(--color-on-danger);box-shadow:0 2px 9px -1px color-mix(in srgb,var(--color-danger-btn) 46%,transparent),inset 0 1px 0 rgba(255,255,255,.22);}
|
|
19
27
|
.fdy-btn--danger:hover{transform:translateY(-1px);box-shadow:0 6px 18px -2px color-mix(in srgb,var(--color-danger-btn) 54%,transparent),inset 0 1px 0 rgba(255,255,255,.22);}
|
|
20
28
|
.fdy-btn--danger:active{transform:translateY(1px);}
|
|
29
|
+
.fdy-btn--danger[aria-pressed="true"]{background:linear-gradient(180deg,color-mix(in srgb,#000 14%,var(--color-danger-btn)),var(--color-danger-btn));box-shadow:inset 0 2px 6px color-mix(in srgb,#000 24%,transparent);}
|
|
21
30
|
|
|
22
31
|
.fdy-btn--sm{height:calc(var(--control-h) - var(--space-2));padding:0 var(--space-3);font-size:var(--text-xs);border-radius:var(--radius-sm);}
|
|
23
32
|
.fdy-btn--lg{height:calc(var(--control-h) + var(--space-2));padding:0 var(--space-6);font-size:var(--text-base);border-radius:var(--radius-lg);}
|
|
@@ -30,6 +39,11 @@
|
|
|
30
39
|
.fdy-btn--text{background:none;color:var(--color-primary-strong);border-color:transparent;box-shadow:none;}
|
|
31
40
|
.fdy-btn--text:hover{transform:none;background:var(--color-primary-soft);box-shadow:none;}
|
|
32
41
|
.fdy-btn--text:active{transform:translateY(1px);box-shadow:none;}
|
|
42
|
+
/* Ghost/text pressed: the kit's selected-surface pair (soft fill + strong ink) — the same pairing
|
|
43
|
+
.fdy-nav__item uses for the current page, and one the AA contrast gate already covers. This is
|
|
44
|
+
the realistic segmented control: a row of --ghost buttons with exactly one aria-pressed. */
|
|
45
|
+
.fdy-btn--ghost[aria-pressed="true"],.fdy-btn--text[aria-pressed="true"]{background:var(--color-primary-soft);color:var(--color-primary-strong);border-color:var(--color-primary-border);box-shadow:none;}
|
|
46
|
+
.fdy-btn--ghost[aria-pressed="true"]:hover,.fdy-btn--text[aria-pressed="true"]:hover{background:var(--color-primary-soft);transform:none;box-shadow:none;}
|
|
33
47
|
|
|
34
48
|
/* Icon-only — square; combine with --ghost/--text/--sm/--lg. Requires aria-label. */
|
|
35
49
|
.fdy-btn--icon{width:var(--control-h);padding:0;}
|
package/src/components/card.css
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* Freeday — Card */
|
|
2
|
-
|
|
2
|
+
/* position:relative — containing block for out-of-flow card content (see base.css); it also gives
|
|
3
|
+
consumers the anchor a corner ribbon/badge needs. */
|
|
4
|
+
.fdy-card{position:relative;background:var(--color-surface);border:var(--bw) solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-lift);transition:box-shadow var(--dur-base) var(--ease-standard),transform var(--dur-base) var(--ease-standard);}
|
|
3
5
|
.fdy-card--elevated{box-shadow:var(--shadow-lift-hover);}
|
|
4
6
|
.fdy-card--interactive{cursor:pointer;}
|
|
5
7
|
.fdy-card--interactive:hover{box-shadow:var(--shadow-lift-hover);transform:translateY(-3px);}
|
|
@@ -10,6 +12,10 @@
|
|
|
10
12
|
* announced — reset the UA button box. Note: it does NOT reset background/border, because
|
|
11
13
|
* .fdy-card already sets its own surface + border (resetting them here would strip the card). */
|
|
12
14
|
.fdy-card--button{display:block;width:100%;text-align:inherit;color:inherit;appearance:none;-webkit-appearance:none;}
|
|
15
|
+
/* Disabled card-as-control — same contract as .fdy-list__row--button: dim + not-allowed, and the
|
|
16
|
+
--interactive lift is withdrawn so a refusing control stops answering the pointer. */
|
|
17
|
+
.fdy-card--button:disabled,.fdy-card--button[aria-disabled="true"],.fdy-card--interactive[aria-disabled="true"]{opacity:.5;cursor:not-allowed;}
|
|
18
|
+
.fdy-card--interactive:disabled:hover,.fdy-card--interactive[aria-disabled="true"]:hover{box-shadow:var(--shadow-lift);transform:none;}
|
|
13
19
|
.fdy-card__body{padding:var(--space-5);}
|
|
14
20
|
.fdy-card__title{font-family:var(--font-display);font-size:var(--text-lg);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-tight);color:var(--color-text);margin:0 0 var(--space-1);}
|
|
15
21
|
.fdy-card__desc{font-size:var(--text-sm);color:var(--color-text-muted);margin:0;line-height:var(--leading-normal);}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/* Freeday — Carousel (scroll-snap track + arrows + dots). Enhanced by freeday-carousel.js. */
|
|
2
2
|
.fdy-carousel{position:relative;}
|
|
3
|
-
.fdy-
|
|
3
|
+
/* position:relative — the arrows are positioned against .fdy-carousel (the parent), so this only
|
|
4
|
+
catches out-of-flow content inside the SLIDES, which would otherwise escape the viewport
|
|
5
|
+
entirely and scroll the page by one slide-offset per slide (see base.css). */
|
|
6
|
+
.fdy-carousel__viewport{position:relative;display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scroll-behavior:smooth;border-radius:var(--radius-lg);scrollbar-width:none;-ms-overflow-style:none;}
|
|
4
7
|
.fdy-carousel__viewport::-webkit-scrollbar{display:none;}
|
|
5
8
|
.fdy-carousel__slide{flex:0 0 100%;min-width:0;scroll-snap-align:center;}
|
|
6
9
|
.fdy-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border:0;border-radius:var(--radius-full);background:color-mix(in srgb,var(--color-surface) 86%,transparent);color:var(--color-text);box-shadow:var(--shadow-2);cursor:pointer;transition:background var(--dur-fast) var(--ease-standard);}
|
package/src/components/list.css
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Not to be confused with .fdy-list-reset (base.css), which only strips UA bullets/indent.
|
|
10
10
|
* Works on <ul>/<ol> (list-style is reset here) or on plain <div>s. */
|
|
11
|
-
|
|
11
|
+
/* position:relative — containing block for out-of-flow row content (see base.css). */
|
|
12
|
+
.fdy-list{position:relative;list-style:none;margin:0;padding:0;background:var(--color-surface);border:var(--bw) solid var(--color-border);border-radius:var(--radius-lg);overflow:hidden;}
|
|
12
13
|
.fdy-list__row{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-4) var(--space-5);min-width:0;}
|
|
13
14
|
/* Divider between rows. Two shapes are supported and both are load-bearing: rows as direct children
|
|
14
15
|
* of the list, and rows wrapped in <li> (the semantic shape, where the ADJACENT siblings are the
|
|
@@ -21,6 +22,12 @@
|
|
|
21
22
|
.fdy-list__row--button:hover,.fdy-list__row--interactive:hover{background:var(--color-surface-2);}
|
|
22
23
|
.fdy-list__row--button:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--color-primary);}
|
|
23
24
|
.fdy-list__row--interactive{cursor:pointer;}
|
|
25
|
+
/* Disabled row. The reset above adopts the UA button box, but not its disabled state — so a row
|
|
26
|
+
disabled mid-flight (a redirect in progress, say) kept lighting up and kept a pointer cursor:
|
|
27
|
+
a control answering the pointer while refusing input. Same contract as every other disabled
|
|
28
|
+
control in the kit (dim + not-allowed), hover withdrawn, both the native and the aria- form. */
|
|
29
|
+
.fdy-list__row--button:disabled,.fdy-list__row--button[aria-disabled="true"],.fdy-list__row--interactive[aria-disabled="true"]{opacity:.5;cursor:not-allowed;}
|
|
30
|
+
.fdy-list__row--button:disabled:hover,.fdy-list__row--button[aria-disabled="true"]:hover,.fdy-list__row--interactive[aria-disabled="true"]:hover{background:none;}
|
|
24
31
|
/* Row internals: a title/meta stack that truncates, and a trailing slot pinned right. */
|
|
25
32
|
.fdy-list__main{display:flex;flex-direction:column;gap:var(--space-1);min-width:0;flex:1;}
|
|
26
33
|
.fdy-list__title{font-weight:var(--weight-medium);color:var(--color-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
package/src/components/table.css
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/* Freeday — Table */
|
|
2
|
-
|
|
2
|
+
/* position:relative on every scroller/clipper — it makes the box the containing block for its own
|
|
3
|
+
absolutely positioned content (.fdy-visually-hidden above all), which `overflow` alone does NOT
|
|
4
|
+
clip. Without it a hidden label in a wide table scrolls the whole page. See base.css. */
|
|
5
|
+
.fdy-table-wrap{position:relative;overflow-x:auto;border:var(--bw) solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-1);background:var(--color-surface);}
|
|
3
6
|
.fdy-table{width:100%;border-collapse:collapse;font-size:var(--text-sm);}
|
|
4
7
|
.fdy-table caption{text-align:left;padding:var(--space-3) var(--space-4);font-weight:var(--weight-semibold);color:var(--color-text);}
|
|
5
8
|
.fdy-table th{text-align:left;padding:var(--space-3) var(--space-4);font-size:var(--text-xs);font-weight:var(--weight-semibold);text-transform:uppercase;letter-spacing:var(--tracking-wide);color:var(--color-text-muted);background:var(--color-surface-2);border-bottom:var(--bw) solid var(--color-border);white-space:nowrap;}
|
|
@@ -36,7 +39,7 @@
|
|
|
36
39
|
|
|
37
40
|
/* Data-table shell (toolbar + scroll + footer stay put while the table scrolls) */
|
|
38
41
|
.fdy-datatable{border:var(--bw) solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-1);background:var(--color-surface);overflow:hidden;}
|
|
39
|
-
.fdy-table-scroll{overflow-x:auto;}
|
|
42
|
+
.fdy-table-scroll{position:relative;overflow-x:auto;}
|
|
40
43
|
.fdy-table-toolbar{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap;padding:var(--space-3) var(--space-4);border-bottom:var(--bw) solid var(--color-border);}
|
|
41
44
|
.fdy-table-toolbar__search{max-width:18rem;}
|
|
42
45
|
.fdy-table-toolbar__spacer{flex:1;}
|
package/src/components/tabs.css
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
/* Freeday — Tabs (WAI-ARIA APG) */
|
|
2
|
-
|
|
2
|
+
/* position:relative — containing block for out-of-flow content in the tabs (see base.css). */
|
|
3
|
+
.fdy-tabs__list{position:relative;display:flex;gap:var(--space-1);border-bottom:var(--bw) solid var(--color-border);overflow-x:auto;}
|
|
3
4
|
.fdy-tabs__tab{appearance:none;border:0;background:transparent;cursor:pointer;white-space:nowrap;font-family:var(--font-body);font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text-muted);padding:var(--space-3) var(--space-4);border-bottom:2px solid transparent;margin-bottom:-1px;transition:color var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard);}
|
|
4
5
|
.fdy-tabs__tab:hover{color:var(--color-text);}
|
|
5
6
|
.fdy-tabs__tab:disabled,.fdy-tabs__tab[aria-disabled="true"]{opacity:.5;cursor:not-allowed;color:var(--color-text-muted);}
|
|
6
7
|
.fdy-tabs__tab:disabled:hover,.fdy-tabs__tab[aria-disabled="true"]:hover{color:var(--color-text-muted);}
|
|
7
|
-
|
|
8
|
+
/* `aria-current="page"` is honoured alongside `aria-selected="true"` so the tab look can be used for
|
|
9
|
+
ROUTE-driven sub-navigation (/settings/profile · /settings/billing), where the tabs are real links.
|
|
10
|
+
A link cannot be `aria-selected` — that is invalid ARIA on an anchor; `aria-current` is the only
|
|
11
|
+
correct marker, and it is what a router sets. Use `.fdy-tabs` + `freeday-tabs.js` (roving tabindex,
|
|
12
|
+
a panel per tab) for in-page tabs; use these classes on plain links for routed ones, and
|
|
13
|
+
`.fdy-nav--horizontal` for an application's PRIMARY navigation. */
|
|
14
|
+
.fdy-tabs__tab[aria-selected="true"],.fdy-tabs__tab[aria-current="page"]{color:var(--color-primary-strong);border-bottom-color:var(--color-primary);}
|
|
8
15
|
.fdy-tabs__tab:focus-visible{outline:none;border-radius:var(--radius-sm);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary) 26%,transparent);}
|
|
9
16
|
.fdy-tabs__panel{padding:var(--space-5) 0;}
|
|
10
17
|
.fdy-tabs__panel[hidden]{display:none;}
|