Modern Native Dark Mode with the CSS light-dark() Function and color-scheme
The cutting-edge, media-query-free approach. Declare color-scheme: light dark; once, then write every color as light-dark(<light-value>, <dark-value>) — the browser picks the right one based on the resolved scheme, with no @media block and no duplicated rule set. Manual override becomes a one-liner: change color-scheme to light or dark. This is where CSS dark mode is heading.
Published
The code
<section class="cdm-05" data-scheme="system">
<div class="cdm-05__card">
<span class="cdm-05__tag">light-dark() · no @media</span>
<h1>One value, both themes</h1>
<p>Every color here is written once as <code>light-dark(light, dark)</code>. The switch below just rewrites <code>color-scheme</code> — there isn't a single media query in the CSS.</p>
<div class="cdm-05__seg" role="radiogroup" aria-label="Color scheme">
<label><input type="radio" name="cdm5" value="system" checked><span>System</span></label>
<label><input type="radio" name="cdm5" value="light"><span>Light</span></label>
<label><input type="radio" name="cdm5" value="dark"><span>Dark</span></label>
</div>
<div class="cdm-05__demorow">
<select class="cdm-05__native" aria-label="Native select follows color-scheme"><option>Native controls follow color-scheme</option><option>No custom scrollbar CSS needed</option></select>
</div>
</div>
</section><section class="cdm-05" data-scheme="system">
<div class="cdm-05__card">
<span class="cdm-05__tag">light-dark() · no @media</span>
<h1>One value, both themes</h1>
<p>Every color here is written once as <code>light-dark(light, dark)</code>. The switch below just rewrites <code>color-scheme</code> — there isn't a single media query in the CSS.</p>
<div class="cdm-05__seg" role="radiogroup" aria-label="Color scheme">
<label><input type="radio" name="cdm5" value="system" checked><span>System</span></label>
<label><input type="radio" name="cdm5" value="light"><span>Light</span></label>
<label><input type="radio" name="cdm5" value="dark"><span>Dark</span></label>
</div>
<div class="cdm-05__demorow">
<select class="cdm-05__native" aria-label="Native select follows color-scheme"><option>Native controls follow color-scheme</option><option>No custom scrollbar CSS needed</option></select>
</div>
</div>
</section>.cdm-05,
.cdm-05 *,
.cdm-05 *::before,
.cdm-05 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cdm-05 {
color-scheme: light dark;
--accent: light-dark(oklch(0.55 0.19 25),oklch(0.74 0.17 25));
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
min-height: 100dvh;
padding: 32px;
font-family: system-ui,'Segoe UI',sans-serif;
background: light-dark(oklch(0.98 0.004 60),oklch(0.16 0.02 30));
color: light-dark(oklch(0.24 0.02 40),oklch(0.95 0.005 40));
}
.cdm-05[data-scheme="light"] {
color-scheme: light;
}
.cdm-05[data-scheme="dark"] {
color-scheme: dark;
}
.cdm-05__card {
width: min(440px,100%);
display: flex;
flex-direction: column;
gap: 16px;
padding: 30px;
border-radius: 20px;
/* surface tint DERIVED from --accent with relative color syntax */
background: light-dark(oklch(1 0 0),oklch(from var(--accent) 0.22 calc(c*0.35) h));
/* elevation swap: soft drop shadow in light, inset border-glow in dark */
box-shadow: light-dark(0 18px 46px -22px oklch(0 0 0 / .35),0 0 0 1px oklch(1 0 0 / .12) inset);
}
.cdm-05__tag {
align-self: flex-start;
padding: 5px 11px;
border-radius: 999px;
font: 600 11px/1 ui-monospace,Menlo,monospace;
color: #fff;
background: var(--accent);
}
.cdm-05__card h1 {
font: 700 clamp(22px,4vw,30px)/1.15 system-ui,sans-serif;
letter-spacing: -.01em;
}
.cdm-05__card p {
font: 400 14.5px/1.6 system-ui,sans-serif;
color: light-dark(oklch(0.45 0.02 40),oklch(0.72 0.02 40));
text-wrap: pretty;
}
.cdm-05 code {
font: 600 12.5px/1 ui-monospace,Menlo,monospace;
padding: 2px 5px;
border-radius: 5px;
background: light-dark(oklch(0.94 0.006 60),oklch(0.26 0.02 40));
color: inherit;
}
.cdm-05__seg {
display: grid;
grid-template-columns: repeat(3,1fr);
gap: 4px;
padding: 4px;
border-radius: 12px;
background: light-dark(oklch(0.95 0.006 60),oklch(0.22 0.02 40));
}
.cdm-05__seg label {
position: relative;
}
.cdm-05__seg input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.cdm-05__seg span {
display: flex;
align-items: center;
justify-content: center;
min-height: 40px;
border-radius: 8px;
font: 600 13px/1 system-ui,sans-serif;
color: light-dark(oklch(0.45 0.02 40),oklch(0.72 0.02 40));
transition: background-color .2s ease,color .2s ease;
}
.cdm-05__seg input:checked + span {
background: light-dark(oklch(1 0 0),oklch(0.3 0.02 40));
color: light-dark(oklch(0.24 0.02 40),oklch(0.97 0.005 40));
box-shadow: 0 1px 4px oklch(0 0 0 / .2);
}
.cdm-05__seg input:focus-visible + span {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.cdm-05__native {
min-height: 44px;
padding: 0 12px;
border-radius: 10px;
border: 1px solid light-dark(oklch(0.9 0.008 60),oklch(0.32 0.02 40));
background: light-dark(oklch(1 0 0),oklch(0.2 0.02 40));
color: inherit;
font: 400 14px/1 system-ui,sans-serif;
width: 100%;
}
.cdm-05__native:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
.cdm-05 * {
transition: none!important;
}
}.cdm-05,
.cdm-05 *,
.cdm-05 *::before,
.cdm-05 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cdm-05 {
color-scheme: light dark;
--accent: light-dark(oklch(0.55 0.19 25),oklch(0.74 0.17 25));
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
min-height: 100dvh;
padding: 32px;
font-family: system-ui,'Segoe UI',sans-serif;
background: light-dark(oklch(0.98 0.004 60),oklch(0.16 0.02 30));
color: light-dark(oklch(0.24 0.02 40),oklch(0.95 0.005 40));
}
.cdm-05[data-scheme="light"] {
color-scheme: light;
}
.cdm-05[data-scheme="dark"] {
color-scheme: dark;
}
.cdm-05__card {
width: min(440px,100%);
display: flex;
flex-direction: column;
gap: 16px;
padding: 30px;
border-radius: 20px;
/* surface tint DERIVED from --accent with relative color syntax */
background: light-dark(oklch(1 0 0),oklch(from var(--accent) 0.22 calc(c*0.35) h));
/* elevation swap: soft drop shadow in light, inset border-glow in dark */
box-shadow: light-dark(0 18px 46px -22px oklch(0 0 0 / .35),0 0 0 1px oklch(1 0 0 / .12) inset);
}
.cdm-05__tag {
align-self: flex-start;
padding: 5px 11px;
border-radius: 999px;
font: 600 11px/1 ui-monospace,Menlo,monospace;
color: #fff;
background: var(--accent);
}
.cdm-05__card h1 {
font: 700 clamp(22px,4vw,30px)/1.15 system-ui,sans-serif;
letter-spacing: -.01em;
}
.cdm-05__card p {
font: 400 14.5px/1.6 system-ui,sans-serif;
color: light-dark(oklch(0.45 0.02 40),oklch(0.72 0.02 40));
text-wrap: pretty;
}
.cdm-05 code {
font: 600 12.5px/1 ui-monospace,Menlo,monospace;
padding: 2px 5px;
border-radius: 5px;
background: light-dark(oklch(0.94 0.006 60),oklch(0.26 0.02 40));
color: inherit;
}
.cdm-05__seg {
display: grid;
grid-template-columns: repeat(3,1fr);
gap: 4px;
padding: 4px;
border-radius: 12px;
background: light-dark(oklch(0.95 0.006 60),oklch(0.22 0.02 40));
}
.cdm-05__seg label {
position: relative;
}
.cdm-05__seg input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.cdm-05__seg span {
display: flex;
align-items: center;
justify-content: center;
min-height: 40px;
border-radius: 8px;
font: 600 13px/1 system-ui,sans-serif;
color: light-dark(oklch(0.45 0.02 40),oklch(0.72 0.02 40));
transition: background-color .2s ease,color .2s ease;
}
.cdm-05__seg input:checked + span {
background: light-dark(oklch(1 0 0),oklch(0.3 0.02 40));
color: light-dark(oklch(0.24 0.02 40),oklch(0.97 0.005 40));
box-shadow: 0 1px 4px oklch(0 0 0 / .2);
}
.cdm-05__seg input:focus-visible + span {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.cdm-05__native {
min-height: 44px;
padding: 0 12px;
border-radius: 10px;
border: 1px solid light-dark(oklch(0.9 0.008 60),oklch(0.32 0.02 40));
background: light-dark(oklch(1 0 0),oklch(0.2 0.02 40));
color: inherit;
font: 400 14px/1 system-ui,sans-serif;
width: 100%;
}
.cdm-05__native:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
.cdm-05 * {
transition: none!important;
}
}(function () {
var root = document.querySelector('.cdm-05');
var radios = root.querySelectorAll('input[name="cdm5"]');
radios.forEach(function (r) {
r.addEventListener('change', function () {
// the ENTIRE switch: rewrite color-scheme; light-dark() re-resolves every color
root.dataset.scheme = r.value;
});
});
})();(function () {
var root = document.querySelector('.cdm-05');
var radios = root.querySelectorAll('input[name="cdm5"]');
radios.forEach(function (r) {
r.addEventListener('change', function () {
// the ENTIRE switch: rewrite color-scheme; light-dark() re-resolves every color
root.dataset.scheme = r.value;
});
});
})();Here's a working CSS Variable Dark Mode System from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Modern Native Dark Mode with the CSS light-dark() Function and color-scheme
Source: https://codefronts.com/snippets/css-variable-dark-mode-system/light-dark-function-native-css/
The cutting-edge, media-query-free approach. Declare color-scheme: light dark; once, then write every color as light-dark(<light-value>, <dark-value>) — the browser picks the right one based on the resolved scheme, with no @media block and no duplicated rule set. Manual override becomes a one-liner: change color-scheme to light or dark. This is where CSS dark mode is heading.
## HTML
```html
<section class="cdm-05" data-scheme="system">
<div class="cdm-05__card">
<span class="cdm-05__tag">light-dark() · no @media</span>
<h1>One value, both themes</h1>
<p>Every color here is written once as <code>light-dark(light, dark)</code>. The switch below just rewrites <code>color-scheme</code> — there isn't a single media query in the CSS.</p>
<div class="cdm-05__seg" role="radiogroup" aria-label="Color scheme">
<label><input type="radio" name="cdm5" value="system" checked><span>System</span></label>
<label><input type="radio" name="cdm5" value="light"><span>Light</span></label>
<label><input type="radio" name="cdm5" value="dark"><span>Dark</span></label>
</div>
<div class="cdm-05__demorow">
<select class="cdm-05__native" aria-label="Native select follows color-scheme"><option>Native controls follow color-scheme</option><option>No custom scrollbar CSS needed</option></select>
</div>
</div>
</section>
```
## CSS
```css
.cdm-05,
.cdm-05 *,
.cdm-05 *::before,
.cdm-05 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cdm-05 {
color-scheme: light dark;
--accent: light-dark(oklch(0.55 0.19 25),oklch(0.74 0.17 25));
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
min-height: 100dvh;
padding: 32px;
font-family: system-ui,'Segoe UI',sans-serif;
background: light-dark(oklch(0.98 0.004 60),oklch(0.16 0.02 30));
color: light-dark(oklch(0.24 0.02 40),oklch(0.95 0.005 40));
}
.cdm-05[data-scheme="light"] {
color-scheme: light;
}
.cdm-05[data-scheme="dark"] {
color-scheme: dark;
}
.cdm-05__card {
width: min(440px,100%);
display: flex;
flex-direction: column;
gap: 16px;
padding: 30px;
border-radius: 20px;
/* surface tint DERIVED from --accent with relative color syntax */
background: light-dark(oklch(1 0 0),oklch(from var(--accent) 0.22 calc(c*0.35) h));
/* elevation swap: soft drop shadow in light, inset border-glow in dark */
box-shadow: light-dark(0 18px 46px -22px oklch(0 0 0 / .35),0 0 0 1px oklch(1 0 0 / .12) inset);
}
.cdm-05__tag {
align-self: flex-start;
padding: 5px 11px;
border-radius: 999px;
font: 600 11px/1 ui-monospace,Menlo,monospace;
color: #fff;
background: var(--accent);
}
.cdm-05__card h1 {
font: 700 clamp(22px,4vw,30px)/1.15 system-ui,sans-serif;
letter-spacing: -.01em;
}
.cdm-05__card p {
font: 400 14.5px/1.6 system-ui,sans-serif;
color: light-dark(oklch(0.45 0.02 40),oklch(0.72 0.02 40));
text-wrap: pretty;
}
.cdm-05 code {
font: 600 12.5px/1 ui-monospace,Menlo,monospace;
padding: 2px 5px;
border-radius: 5px;
background: light-dark(oklch(0.94 0.006 60),oklch(0.26 0.02 40));
color: inherit;
}
.cdm-05__seg {
display: grid;
grid-template-columns: repeat(3,1fr);
gap: 4px;
padding: 4px;
border-radius: 12px;
background: light-dark(oklch(0.95 0.006 60),oklch(0.22 0.02 40));
}
.cdm-05__seg label {
position: relative;
}
.cdm-05__seg input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.cdm-05__seg span {
display: flex;
align-items: center;
justify-content: center;
min-height: 40px;
border-radius: 8px;
font: 600 13px/1 system-ui,sans-serif;
color: light-dark(oklch(0.45 0.02 40),oklch(0.72 0.02 40));
transition: background-color .2s ease,color .2s ease;
}
.cdm-05__seg input:checked + span {
background: light-dark(oklch(1 0 0),oklch(0.3 0.02 40));
color: light-dark(oklch(0.24 0.02 40),oklch(0.97 0.005 40));
box-shadow: 0 1px 4px oklch(0 0 0 / .2);
}
.cdm-05__seg input:focus-visible + span {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.cdm-05__native {
min-height: 44px;
padding: 0 12px;
border-radius: 10px;
border: 1px solid light-dark(oklch(0.9 0.008 60),oklch(0.32 0.02 40));
background: light-dark(oklch(1 0 0),oklch(0.2 0.02 40));
color: inherit;
font: 400 14px/1 system-ui,sans-serif;
width: 100%;
}
.cdm-05__native:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
.cdm-05 * {
transition: none!important;
}
}
```
## JavaScript
```js
(function () {
var root = document.querySelector('.cdm-05');
var radios = root.querySelectorAll('input[name="cdm5"]');
radios.forEach(function (r) {
r.addEventListener('change', function () {
// the ENTIRE switch: rewrite color-scheme; light-dark() re-resolves every color
root.dataset.scheme = r.value;
});
});
})();
```Here's a working CSS Variable Dark Mode System from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Modern Native Dark Mode with the CSS light-dark() Function and color-scheme
Source: https://codefronts.com/snippets/css-variable-dark-mode-system/light-dark-function-native-css/
The cutting-edge, media-query-free approach. Declare color-scheme: light dark; once, then write every color as light-dark(<light-value>, <dark-value>) — the browser picks the right one based on the resolved scheme, with no @media block and no duplicated rule set. Manual override becomes a one-liner: change color-scheme to light or dark. This is where CSS dark mode is heading.
## HTML
```html
<section class="cdm-05" data-scheme="system">
<div class="cdm-05__card">
<span class="cdm-05__tag">light-dark() · no @media</span>
<h1>One value, both themes</h1>
<p>Every color here is written once as <code>light-dark(light, dark)</code>. The switch below just rewrites <code>color-scheme</code> — there isn't a single media query in the CSS.</p>
<div class="cdm-05__seg" role="radiogroup" aria-label="Color scheme">
<label><input type="radio" name="cdm5" value="system" checked><span>System</span></label>
<label><input type="radio" name="cdm5" value="light"><span>Light</span></label>
<label><input type="radio" name="cdm5" value="dark"><span>Dark</span></label>
</div>
<div class="cdm-05__demorow">
<select class="cdm-05__native" aria-label="Native select follows color-scheme"><option>Native controls follow color-scheme</option><option>No custom scrollbar CSS needed</option></select>
</div>
</div>
</section>
```
## CSS
```css
.cdm-05,
.cdm-05 *,
.cdm-05 *::before,
.cdm-05 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.cdm-05 {
color-scheme: light dark;
--accent: light-dark(oklch(0.55 0.19 25),oklch(0.74 0.17 25));
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
min-height: 100dvh;
padding: 32px;
font-family: system-ui,'Segoe UI',sans-serif;
background: light-dark(oklch(0.98 0.004 60),oklch(0.16 0.02 30));
color: light-dark(oklch(0.24 0.02 40),oklch(0.95 0.005 40));
}
.cdm-05[data-scheme="light"] {
color-scheme: light;
}
.cdm-05[data-scheme="dark"] {
color-scheme: dark;
}
.cdm-05__card {
width: min(440px,100%);
display: flex;
flex-direction: column;
gap: 16px;
padding: 30px;
border-radius: 20px;
/* surface tint DERIVED from --accent with relative color syntax */
background: light-dark(oklch(1 0 0),oklch(from var(--accent) 0.22 calc(c*0.35) h));
/* elevation swap: soft drop shadow in light, inset border-glow in dark */
box-shadow: light-dark(0 18px 46px -22px oklch(0 0 0 / .35),0 0 0 1px oklch(1 0 0 / .12) inset);
}
.cdm-05__tag {
align-self: flex-start;
padding: 5px 11px;
border-radius: 999px;
font: 600 11px/1 ui-monospace,Menlo,monospace;
color: #fff;
background: var(--accent);
}
.cdm-05__card h1 {
font: 700 clamp(22px,4vw,30px)/1.15 system-ui,sans-serif;
letter-spacing: -.01em;
}
.cdm-05__card p {
font: 400 14.5px/1.6 system-ui,sans-serif;
color: light-dark(oklch(0.45 0.02 40),oklch(0.72 0.02 40));
text-wrap: pretty;
}
.cdm-05 code {
font: 600 12.5px/1 ui-monospace,Menlo,monospace;
padding: 2px 5px;
border-radius: 5px;
background: light-dark(oklch(0.94 0.006 60),oklch(0.26 0.02 40));
color: inherit;
}
.cdm-05__seg {
display: grid;
grid-template-columns: repeat(3,1fr);
gap: 4px;
padding: 4px;
border-radius: 12px;
background: light-dark(oklch(0.95 0.006 60),oklch(0.22 0.02 40));
}
.cdm-05__seg label {
position: relative;
}
.cdm-05__seg input {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: pointer;
}
.cdm-05__seg span {
display: flex;
align-items: center;
justify-content: center;
min-height: 40px;
border-radius: 8px;
font: 600 13px/1 system-ui,sans-serif;
color: light-dark(oklch(0.45 0.02 40),oklch(0.72 0.02 40));
transition: background-color .2s ease,color .2s ease;
}
.cdm-05__seg input:checked + span {
background: light-dark(oklch(1 0 0),oklch(0.3 0.02 40));
color: light-dark(oklch(0.24 0.02 40),oklch(0.97 0.005 40));
box-shadow: 0 1px 4px oklch(0 0 0 / .2);
}
.cdm-05__seg input:focus-visible + span {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.cdm-05__native {
min-height: 44px;
padding: 0 12px;
border-radius: 10px;
border: 1px solid light-dark(oklch(0.9 0.008 60),oklch(0.32 0.02 40));
background: light-dark(oklch(1 0 0),oklch(0.2 0.02 40));
color: inherit;
font: 400 14px/1 system-ui,sans-serif;
width: 100%;
}
.cdm-05__native:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
.cdm-05 * {
transition: none!important;
}
}
```
## JavaScript
```js
(function () {
var root = document.querySelector('.cdm-05');
var radios = root.querySelectorAll('input[name="cdm5"]');
radios.forEach(function (r) {
r.addEventListener('change', function () {
// the ENTIRE switch: rewrite color-scheme; light-dark() re-resolves every color
root.dataset.scheme = r.value;
});
});
})();
```How this works
light-dark() is a native CSS function that returns its first argument in light mode and its second in dark mode, decided by the element's computed color-scheme. Set color-scheme: light dark on the root and the page follows the OS by default; set it to light or dark (here, via a data-theme attribute) and you force an override — no media query anywhere. Because each variable is defined once with both values inline, you keep a single rule set instead of a light block plus a dark block.
This demo also shows two Pro-tier techniques that light-dark() makes trivial: relative color syntax — oklch(from var(--accent) …) derives the surface tint from the accent instead of hand-picking it — and elevation/shadow swapping, where the card's shadow is a soft drop shadow in light mode but a subtle inset border-glow in dark mode, all in one box-shadow: light-dark(…, …) declaration. The three-way control just rewrites color-scheme.
Techniques used: native light-dark() function · color-scheme: light dark as the switch · no @media / no duplicate rule blocks · oklch() relative color syntax (from var()) · elevation/shadow swap via light-dark() · one-line manual override (change color-scheme)
:root { color-scheme: light dark; } /* follow OS; toggle to light|dark to force */
.card {
background: light-dark(#ffffff, #1a1a20); /* 1st = light, 2nd = dark */
color: light-dark(#18181b, #f4f4f5);
box-shadow: light-dark(0 6px 20px rgba(0,0,0,.1), 0 0 0 1px rgba(255,255,255,.12));
}Make it yours
- Combine with custom properties: store the pairs (
--card: light-dark(#fff,#1a1a20)) and referencevar(--card)everywhere. - Force a theme per component (not just per page) by setting
color-schemeon any subtree —light-dark()resolves per element. - Derive an entire dark ramp from one hue with relative color:
oklch(from var(--accent) calc(l - .4) c h). - Fall back for older browsers with an
@supports not (color: light-dark(#000,#fff))block using the Demo 01 media-query approach.
Gotchas — read before shipping
light-dark()only works whencolor-schemeincludes both keywords on (or above) the element — without it the function has nothing to resolve against.- Browser support is 2024+; gate anything critical behind
@supportsand ship the prefers-color-scheme fallback for older engines. - Setting
color-schemeto a single value is what forces an override — remember to restorelight darkto return to "follow OS". - It resolves colors only; it can't switch non-color values like
background-imageURLs.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 123+ | 17.5+ | 120+ | 123+ |
light-dark() shipped across all three engines in 2024. It's the newest technique here — always pair with an @supports fallback for production traffic.