/*
 * Icons are sourced from Heroicons (https://heroicons.com/).
 * The source SVG files live in the project's assets/icons directory.
 * Future edits should target the SVG files directly instead of editing long data URIs here.
 */

:root {
    /** General **/
    --ti-font-family: system-ui, -apple-system, segoe ui, roboto, arial, sans-serif;
    --ti-font-size: 14px;
    --ti-gap: 12px;
    --ti-grid-gap: 6px;
    --ti-margin: 12px;
    --ti-padding: 12px;
    --ti-internal-padding: 6px;
    --ti-error-color: rgb(230 96 96 / 95%);
    --ti-icon-size: 24px;
    --ti-icon-color: #a6a6a6;
    --ti-icon-hover-color: #ffffff;
    --ti-icon-color-dark: #353535;
    --ti-icon-hover-color-dark: #4c4c4c;
    /** Widgets **/
    --ti-notification-top: 50px;
    --ti-panel-border-radius: 4px;
    --ti-panel-padding: var(--ti-padding);
    --ti-sub-panel-background: #d9d9d9;
    --ti-border-color: rgba(255, 255, 255, 0.15);
    /** Buttons **/
    --ti-button-gap: 6px;
    --ti-button-radius: 10px;
    --ti-button-size: 44px;
    --ti-button-inline-height: 32px;
    /** Data Fields **/
    --ti-data-field-background-color: #b9b9b9;
    --ti-data-field-border-color: var(--ti-data-field-background-color);
    --ti-data-field-border-radius: 2px;
    --ti-data-field-height: 20px;
    --ti-data-field-padding-h: 12px;
    --ti-data-field-padding-v: 6px;
    --ti-data-field-text-color: #111111;
    --ti-description-color: #353535;
    --ti-input-background-color: #ffffff;
    --ti-input-border-color: #a6a6a6;
    --ti-input-outline-color: #8ba0e3;
    --ti-input-outline-shadow-color: rgba(74, 110, 219, 0.2);
    --ti-label-color: #1f1f1f;
    --ti-label-font-size: 14px;
    --ti-title-color: #1d1d1d;
    --ti-title-font-size: 14px;
}

/*
 * No elastic overscroll anywhere in the shell (1.45.1, CA-354). Edge on Windows stretches a page that is scrolled past
 * its end with a touchpad or a wheel, then lets it spring back; Chrome on Windows does not, so the same screen bounced
 * in one browser and stood still in the other. `none` turns the effect off and ends scroll chaining as well, where
 * `contain` would end only the chaining. It is on the document, from both the root and the body because engines have
 * taken the viewport's value from either, and on each scroller below: `.ti-content.pane`, `.ti-sidebar`,
 * `.ti-page-scrollable` and `.ti-modal-body`. A scroller an application nests inside a page keeps the default and
 * hands its overscroll to the page, which drops it.
 */
html {
    overscroll-behavior: none;
}

body {
    font-family: var(--ti-font-family), system-ui;
    position: absolute;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
    overscroll-behavior: none;
}

.ti-icon {
    display: inline-block;
    width: var(--ti-icon-size, 20px);
    height: var(--ti-icon-size, 20px);
    background-color: currentColor;
    -webkit-mask-image: none;
    mask-image: none;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
    flex-shrink: 0;
    vertical-align: middle;
}

/* Size modifiers — pick the one closest to the surrounding text. xs/sm/md/lg/xl cover the
   10–32px range we use across the app. The bare .ti-icon keeps a sensible 20px default. */
.ti-icon.xs {
    --ti-icon-size: 12px;
}

.ti-icon.sm {
    --ti-icon-size: 14px;
}

.ti-icon.md {
    --ti-icon-size: 16px;
}

.ti-icon.lg {
    --ti-icon-size: 24px;
}

.ti-icon.xl {
    --ti-icon-size: 32px;
}

/* Legacy color modifiers preserved for the user-profile flyout (which still uses the explicit
   gray on a dark sidebar). New screens inherit color from their parent automatically. */
.ti-icon.legacy-gray {
    background-color: var(--ti-icon-color);
}

.ti-icon.legacy-gray:hover {
    background-color: var(--ti-icon-hover-color);
}

.ti-icon.dark-style {
    background-color: var(--ti-icon-color-dark);
}

.ti-icon.dark-style:hover {
    background-color: var(--ti-icon-hover-color-dark);
}

/*
 * -webkit-mask-image: url("data:image/svg+xml,");
 * mask-image: url("data:image/svg+xml,");
 */
.ti-icon.empty {
    -webkit-mask-image: none;
    mask-image: none;
    background-color: transparent;
}

.ti-icon.app-menu {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M3.75%2012h16.5m-16.5%203.75h16.5M3.75%2019.5h16.5M5.625%204.5h12.75a1.875%201.875%200%200%201%200%203.75H5.625a1.875%201.875%200%200%201%200-3.75Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M3.75%2012h16.5m-16.5%203.75h16.5M3.75%2019.5h16.5M5.625%204.5h12.75a1.875%201.875%200%200%201%200%203.75H5.625a1.875%201.875%200%200%201%200-3.75Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.app-menu:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20d%3D%22M5.625%203.75a2.625%202.625%200%201%200%200%205.25h12.75a2.625%202.625%200%200%200%200-5.25H5.625ZM3.75%2011.25a.75.75%200%200%200%200%201.5h16.5a.75.75%200%200%200%200-1.5H3.75ZM3%2015.75a.75.75%200%200%201%20.75-.75h16.5a.75.75%200%200%201%200%201.5H3.75a.75.75%200%200%201-.75-.75ZM3.75%2018.75a.75.75%200%200%200%200%201.5h16.5a.75.75%200%200%200%200-1.5H3.75Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20d%3D%22M5.625%203.75a2.625%202.625%200%201%200%200%205.25h12.75a2.625%202.625%200%200%200%200-5.25H5.625ZM3.75%2011.25a.75.75%200%200%200%200%201.5h16.5a.75.75%200%200%200%200-1.5H3.75ZM3%2015.75a.75.75%200%200%201%20.75-.75h16.5a.75.75%200%200%201%200%201.5H3.75a.75.75%200%200%201-.75-.75ZM3.75%2018.75a.75.75%200%200%200%200%201.5h16.5a.75.75%200%200%200%200-1.5H3.75Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.dashboard {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22m2.25%2012%208.954-8.955c.44-.439%201.152-.439%201.591%200L21.75%2012M4.5%209.75v10.125c0%20.621.504%201.125%201.125%201.125H9.75v-4.875c0-.621.504-1.125%201.125-1.125h2.25c.621%200%201.125.504%201.125%201.125V21h4.125c.621%200%201.125-.504%201.125-1.125V9.75M8.25%2021h8.25%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22m2.25%2012%208.954-8.955c.44-.439%201.152-.439%201.591%200L21.75%2012M4.5%209.75v10.125c0%20.621.504%201.125%201.125%201.125H9.75v-4.875c0-.621.504-1.125%201.125-1.125h2.25c.621%200%201.125.504%201.125%201.125V21h4.125c.621%200%201.125-.504%201.125-1.125V9.75M8.25%2021h8.25%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.dashboard:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20d%3D%22M11.47%203.841a.75.75%200%200%201%201.06%200l8.69%208.69a.75.75%200%201%200%201.06-1.061l-8.689-8.69a2.25%202.25%200%200%200-3.182%200l-8.69%208.69a.75.75%200%201%200%201.061%201.06l8.69-8.689Z%22%20%2F%3E%0A%20%20%3Cpath%20d%3D%22m12%205.432%208.159%208.159c.03.03.06.058.091.086v6.198c0%201.035-.84%201.875-1.875%201.875H15a.75.75%200%200%201-.75-.75v-4.5a.75.75%200%200%200-.75-.75h-3a.75.75%200%200%200-.75.75V21a.75.75%200%200%201-.75.75H5.625a1.875%201.875%200%200%201-1.875-1.875v-6.198a2.29%202.29%200%200%200%20.091-.086L12%205.432Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20d%3D%22M11.47%203.841a.75.75%200%200%201%201.06%200l8.69%208.69a.75.75%200%201%200%201.06-1.061l-8.689-8.69a2.25%202.25%200%200%200-3.182%200l-8.69%208.69a.75.75%200%201%200%201.061%201.06l8.69-8.689Z%22%20%2F%3E%0A%20%20%3Cpath%20d%3D%22m12%205.432%208.159%208.159c.03.03.06.058.091.086v6.198c0%201.035-.84%201.875-1.875%201.875H15a.75.75%200%200%201-.75-.75v-4.5a.75.75%200%200%200-.75-.75h-3a.75.75%200%200%200-.75.75V21a.75.75%200%200%201-.75.75H5.625a1.875%201.875%200%200%201-1.875-1.875v-6.198a2.29%202.29%200%200%200%20.091-.086L12%205.432Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.settings {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M9.594%203.94c.09-.542.56-.94%201.11-.94h2.593c.55%200%201.02.398%201.11.94l.213%201.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257%201.075.124l1.217-.456a1.125%201.125%200%200%201%201.37.49l1.296%202.247a1.125%201.125%200%200%201-.26%201.431l-1.003.827c-.293.241-.438.613-.43.992a7.723%207.723%200%200%201%200%20.255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26%201.43l-1.298%202.247a1.125%201.125%200%200%201-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47%206.47%200%200%201-.22.128c-.331.183-.581.495-.644.869l-.213%201.281c-.09.543-.56.94-1.11.94h-2.594c-.55%200-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52%206.52%200%200%201-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125%201.125%200%200%201-1.369-.49l-1.297-2.247a1.125%201.125%200%200%201%20.26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932%206.932%200%200%201%200-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125%201.125%200%200%201-.26-1.43l1.297-2.247a1.125%201.125%200%200%201%201.37-.491l1.216.456c.356.133.751.072%201.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z%22%20%2F%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M15%2012a3%203%200%201%201-6%200%203%203%200%200%201%206%200Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M9.594%203.94c.09-.542.56-.94%201.11-.94h2.593c.55%200%201.02.398%201.11.94l.213%201.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257%201.075.124l1.217-.456a1.125%201.125%200%200%201%201.37.49l1.296%202.247a1.125%201.125%200%200%201-.26%201.431l-1.003.827c-.293.241-.438.613-.43.992a7.723%207.723%200%200%201%200%20.255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26%201.43l-1.298%202.247a1.125%201.125%200%200%201-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47%206.47%200%200%201-.22.128c-.331.183-.581.495-.644.869l-.213%201.281c-.09.543-.56.94-1.11.94h-2.594c-.55%200-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52%206.52%200%200%201-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125%201.125%200%200%201-1.369-.49l-1.297-2.247a1.125%201.125%200%200%201%20.26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932%206.932%200%200%201%200-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125%201.125%200%200%201-.26-1.43l1.297-2.247a1.125%201.125%200%200%201%201.37-.491l1.216.456c.356.133.751.072%201.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z%22%20%2F%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M15%2012a3%203%200%201%201-6%200%203%203%200%200%201%206%200Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.settings:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M11.078%202.25c-.917%200-1.699.663-1.85%201.567L9.05%204.889c-.02.12-.115.26-.297.348a7.493%207.493%200%200%200-.986.57c-.166.115-.334.126-.45.083L6.3%205.508a1.875%201.875%200%200%200-2.282.819l-.922%201.597a1.875%201.875%200%200%200%20.432%202.385l.84.692c.095.078.17.229.154.43a7.598%207.598%200%200%200%200%201.139c.015.2-.059.352-.153.43l-.841.692a1.875%201.875%200%200%200-.432%202.385l.922%201.597a1.875%201.875%200%200%200%202.282.818l1.019-.382c.115-.043.283-.031.45.082.312.214.641.405.985.57.182.088.277.228.297.35l.178%201.071c.151.904.933%201.567%201.85%201.567h1.844c.916%200%201.699-.663%201.85-1.567l.178-1.072c.02-.12.114-.26.297-.349.344-.165.673-.356.985-.57.167-.114.335-.125.45-.082l1.02.382a1.875%201.875%200%200%200%202.28-.819l.923-1.597a1.875%201.875%200%200%200-.432-2.385l-.84-.692c-.095-.078-.17-.229-.154-.43a7.614%207.614%200%200%200%200-1.139c-.016-.2.059-.352.153-.43l.84-.692c.708-.582.891-1.59.433-2.385l-.922-1.597a1.875%201.875%200%200%200-2.282-.818l-1.02.382c-.114.043-.282.031-.449-.083a7.49%207.49%200%200%200-.985-.57c-.183-.087-.277-.227-.297-.348l-.179-1.072a1.875%201.875%200%200%200-1.85-1.567h-1.843ZM12%2015.75a3.75%203.75%200%201%200%200-7.5%203.75%203.75%200%200%200%200%207.5Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M11.078%202.25c-.917%200-1.699.663-1.85%201.567L9.05%204.889c-.02.12-.115.26-.297.348a7.493%207.493%200%200%200-.986.57c-.166.115-.334.126-.45.083L6.3%205.508a1.875%201.875%200%200%200-2.282.819l-.922%201.597a1.875%201.875%200%200%200%20.432%202.385l.84.692c.095.078.17.229.154.43a7.598%207.598%200%200%200%200%201.139c.015.2-.059.352-.153.43l-.841.692a1.875%201.875%200%200%200-.432%202.385l.922%201.597a1.875%201.875%200%200%200%202.282.818l1.019-.382c.115-.043.283-.031.45.082.312.214.641.405.985.57.182.088.277.228.297.35l.178%201.071c.151.904.933%201.567%201.85%201.567h1.844c.916%200%201.699-.663%201.85-1.567l.178-1.072c.02-.12.114-.26.297-.349.344-.165.673-.356.985-.57.167-.114.335-.125.45-.082l1.02.382a1.875%201.875%200%200%200%202.28-.819l.923-1.597a1.875%201.875%200%200%200-.432-2.385l-.84-.692c-.095-.078-.17-.229-.154-.43a7.614%207.614%200%200%200%200-1.139c-.016-.2.059-.352.153-.43l.84-.692c.708-.582.891-1.59.433-2.385l-.922-1.597a1.875%201.875%200%200%200-2.282-.818l-1.02.382c-.114.043-.282.031-.449-.083a7.49%207.49%200%200%200-.985-.57c-.183-.087-.277-.227-.297-.348l-.179-1.072a1.875%201.875%200%200%200-1.85-1.567h-1.843ZM12%2015.75a3.75%203.75%200%201%200%200-7.5%203.75%203.75%200%200%200%200%207.5Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.error {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M12%209v3.75m9-.75a9%209%200%201%201-18%200%209%209%200%200%201%2018%200Zm-9%203.75h.008v.008H12v-.008Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M12%209v3.75m9-.75a9%209%200%201%201-18%200%209%209%200%200%201%2018%200Zm-9%203.75h.008v.008H12v-.008Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.error:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M2.25%2012c0-5.385%204.365-9.75%209.75-9.75s9.75%204.365%209.75%209.75-4.365%209.75-9.75%209.75S2.25%2017.385%202.25%2012ZM12%208.25a.75.75%200%200%201%20.75.75v3.75a.75.75%200%200%201-1.5%200V9a.75.75%200%200%201%20.75-.75Zm0%208.25a.75.75%200%201%200%200-1.5.75.75%200%200%200%200%201.5Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M2.25%2012c0-5.385%204.365-9.75%209.75-9.75s9.75%204.365%209.75%209.75-4.365%209.75-9.75%209.75S2.25%2017.385%202.25%2012ZM12%208.25a.75.75%200%200%201%20.75.75v3.75a.75.75%200%200%201-1.5%200V9a.75.75%200%200%201%20.75-.75Zm0%208.25a.75.75%200%201%200%200-1.5.75.75%200%200%200%200%201.5Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.user-profile {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M15.75%206a3.75%203.75%200%201%201-7.5%200%203.75%203.75%200%200%201%207.5%200ZM4.501%2020.118a7.5%207.5%200%200%201%2014.998%200A17.933%2017.933%200%200%201%2012%2021.75c-2.676%200-5.216-.584-7.499-1.632Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M15.75%206a3.75%203.75%200%201%201-7.5%200%203.75%203.75%200%200%201%207.5%200ZM4.501%2020.118a7.5%207.5%200%200%201%2014.998%200A17.933%2017.933%200%200%201%2012%2021.75c-2.676%200-5.216-.584-7.499-1.632Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.user-profile:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M7.5%206a4.5%204.5%200%201%201%209%200%204.5%204.5%200%200%201-9%200ZM3.751%2020.105a8.25%208.25%200%200%201%2016.498%200%20.75.75%200%200%201-.437.695A18.683%2018.683%200%200%201%2012%2022.5c-2.786%200-5.433-.608-7.812-1.7a.75.75%200%200%201-.437-.695Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M7.5%206a4.5%204.5%200%201%201%209%200%204.5%204.5%200%200%201-9%200ZM3.751%2020.105a8.25%208.25%200%200%201%2016.498%200%20.75.75%200%200%201-.437.695A18.683%2018.683%200%200%201%2012%2022.5c-2.786%200-5.433-.608-7.812-1.7a.75.75%200%200%201-.437-.695Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.login {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M8.25%209V5.25A2.25%202.25%200%200%201%2010.5%203h6a2.25%202.25%200%200%201%202.25%202.25v13.5A2.25%202.25%200%200%201%2016.5%2021h-6a2.25%202.25%200%200%201-2.25-2.25V15M12%209l3%203m0%200-3%203m3-3H2.25%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M8.25%209V5.25A2.25%202.25%200%200%201%2010.5%203h6a2.25%202.25%200%200%201%202.25%202.25v13.5A2.25%202.25%200%200%201%2016.5%2021h-6a2.25%202.25%200%200%201-2.25-2.25V15M12%209l3%203m0%200-3%203m3-3H2.25%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.login:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M16.5%203.75a1.5%201.5%200%200%201%201.5%201.5v13.5a1.5%201.5%200%200%201-1.5%201.5h-6a1.5%201.5%200%200%201-1.5-1.5V15a.75.75%200%200%200-1.5%200v3.75a3%203%200%200%200%203%203h6a3%203%200%200%200%203-3V5.25a3%203%200%200%200-3-3h-6a3%203%200%200%200-3%203V9A.75.75%200%201%200%209%209V5.25a1.5%201.5%200%200%201%201.5-1.5h6Zm-5.03%204.72a.75.75%200%200%200%200%201.06l1.72%201.72H2.25a.75.75%200%200%200%200%201.5h10.94l-1.72%201.72a.75.75%200%201%200%201.06%201.06l3-3a.75.75%200%200%200%200-1.06l-3-3a.75.75%200%200%200-1.06%200Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M16.5%203.75a1.5%201.5%200%200%201%201.5%201.5v13.5a1.5%201.5%200%200%201-1.5%201.5h-6a1.5%201.5%200%200%201-1.5-1.5V15a.75.75%200%200%200-1.5%200v3.75a3%203%200%200%200%203%203h6a3%203%200%200%200%203-3V5.25a3%203%200%200%200-3-3h-6a3%203%200%200%200-3%203V9A.75.75%200%201%200%209%209V5.25a1.5%201.5%200%200%201%201.5-1.5h6Zm-5.03%204.72a.75.75%200%200%200%200%201.06l1.72%201.72H2.25a.75.75%200%200%200%200%201.5h10.94l-1.72%201.72a.75.75%200%201%200%201.06%201.06l3-3a.75.75%200%200%200%200-1.06l-3-3a.75.75%200%200%200-1.06%200Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.logout {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M15.75%209V5.25A2.25%202.25%200%200%200%2013.5%203h-6a2.25%202.25%200%200%200-2.25%202.25v13.5A2.25%202.25%200%200%200%207.5%2021h6a2.25%202.25%200%200%200%202.25-2.25V15m3%200%203-3m0%200-3-3m3%203H9%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M15.75%209V5.25A2.25%202.25%200%200%200%2013.5%203h-6a2.25%202.25%200%200%200-2.25%202.25v13.5A2.25%202.25%200%200%200%207.5%2021h6a2.25%202.25%200%200%200%202.25-2.25V15m3%200%203-3m0%200-3-3m3%203H9%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.logout:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M7.5%203.75A1.5%201.5%200%200%200%206%205.25v13.5a1.5%201.5%200%200%200%201.5%201.5h6a1.5%201.5%200%200%200%201.5-1.5V15a.75.75%200%200%201%201.5%200v3.75a3%203%200%200%201-3%203h-6a3%203%200%200%201-3-3V5.25a3%203%200%200%201%203-3h6a3%203%200%200%201%203%203V9A.75.75%200%200%201%2015%209V5.25a1.5%201.5%200%200%200-1.5-1.5h-6Zm10.72%204.72a.75.75%200%200%201%201.06%200l3%203a.75.75%200%200%201%200%201.06l-3%203a.75.75%200%201%201-1.06-1.06l1.72-1.72H9a.75.75%200%200%201%200-1.5h10.94l-1.72-1.72a.75.75%200%200%201%200-1.06Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M7.5%203.75A1.5%201.5%200%200%200%206%205.25v13.5a1.5%201.5%200%200%200%201.5%201.5h6a1.5%201.5%200%200%200%201.5-1.5V15a.75.75%200%200%201%201.5%200v3.75a3%203%200%200%201-3%203h-6a3%203%200%200%201-3-3V5.25a3%203%200%200%201%203-3h6a3%203%200%200%201%203%203V9A.75.75%200%200%201%2015%209V5.25a1.5%201.5%200%200%200-1.5-1.5h-6Zm10.72%204.72a.75.75%200%200%201%201.06%200l3%203a.75.75%200%200%201%200%201.06l-3%203a.75.75%200%201%201-1.06-1.06l1.72-1.72H9a.75.75%200%200%201%200-1.5h10.94l-1.72-1.72a.75.75%200%200%201%200-1.06Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.internet {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M12%2021a9.004%209.004%200%200%200%208.716-6.747M12%2021a9.004%209.004%200%200%201-8.716-6.747M12%2021c2.485%200%204.5-4.03%204.5-9S14.485%203%2012%203m0%2018c-2.485%200-4.5-4.03-4.5-9S9.515%203%2012%203m0%200a8.997%208.997%200%200%201%207.843%204.582M12%203a8.997%208.997%200%200%200-7.843%204.582m15.686%200A11.953%2011.953%200%200%201%2012%2010.5c-2.998%200-5.74-1.1-7.843-2.918m15.686%200A8.959%208.959%200%200%201%2021%2012c0%20.778-.099%201.533-.284%202.253m0%200A17.919%2017.919%200%200%201%2012%2016.5c-3.162%200-6.133-.815-8.716-2.247m0%200A9.015%209.015%200%200%201%203%2012c0-1.605.42-3.113%201.157-4.418%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M12%2021a9.004%209.004%200%200%200%208.716-6.747M12%2021a9.004%209.004%200%200%201-8.716-6.747M12%2021c2.485%200%204.5-4.03%204.5-9S14.485%203%2012%203m0%2018c-2.485%200-4.5-4.03-4.5-9S9.515%203%2012%203m0%200a8.997%208.997%200%200%201%207.843%204.582M12%203a8.997%208.997%200%200%200-7.843%204.582m15.686%200A11.953%2011.953%200%200%201%2012%2010.5c-2.998%200-5.74-1.1-7.843-2.918m15.686%200A8.959%208.959%200%200%201%2021%2012c0%20.778-.099%201.533-.284%202.253m0%200A17.919%2017.919%200%200%201%2012%2016.5c-3.162%200-6.133-.815-8.716-2.247m0%200A9.015%209.015%200%200%201%203%2012c0-1.605.42-3.113%201.157-4.418%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.internet:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20d%3D%22M21.721%2012.752a9.711%209.711%200%200%200-.945-5.003%2012.754%2012.754%200%200%201-4.339%202.708%2018.991%2018.991%200%200%201-.214%204.772%2017.165%2017.165%200%200%200%205.498-2.477ZM14.634%2015.55a17.324%2017.324%200%200%200%20.332-4.647c-.952.227-1.945.347-2.966.347-1.021%200-2.014-.12-2.966-.347a17.515%2017.515%200%200%200%20.332%204.647%2017.385%2017.385%200%200%200%205.268%200ZM9.772%2017.119a18.963%2018.963%200%200%200%204.456%200A17.182%2017.182%200%200%201%2012%2021.724a17.18%2017.18%200%200%201-2.228-4.605ZM7.777%2015.23a18.87%2018.87%200%200%201-.214-4.774%2012.753%2012.753%200%200%201-4.34-2.708%209.711%209.711%200%200%200-.944%205.004%2017.165%2017.165%200%200%200%205.498%202.477ZM21.356%2014.752a9.765%209.765%200%200%201-7.478%206.817%2018.64%2018.64%200%200%200%201.988-4.718%2018.627%2018.627%200%200%200%205.49-2.098ZM2.644%2014.752c1.682.971%203.53%201.688%205.49%202.099a18.64%2018.64%200%200%200%201.988%204.718%209.765%209.765%200%200%201-7.478-6.816ZM13.878%202.43a9.755%209.755%200%200%201%206.116%203.986%2011.267%2011.267%200%200%201-3.746%202.504%2018.63%2018.63%200%200%200-2.37-6.49ZM12%202.276a17.152%2017.152%200%200%201%202.805%207.121c-.897.23-1.837.353-2.805.353-.968%200-1.908-.122-2.805-.353A17.151%2017.151%200%200%201%2012%202.276ZM10.122%202.43a18.629%2018.629%200%200%200-2.37%206.49%2011.266%2011.266%200%200%201-3.746-2.504%209.754%209.754%200%200%201%206.116-3.985Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20d%3D%22M21.721%2012.752a9.711%209.711%200%200%200-.945-5.003%2012.754%2012.754%200%200%201-4.339%202.708%2018.991%2018.991%200%200%201-.214%204.772%2017.165%2017.165%200%200%200%205.498-2.477ZM14.634%2015.55a17.324%2017.324%200%200%200%20.332-4.647c-.952.227-1.945.347-2.966.347-1.021%200-2.014-.12-2.966-.347a17.515%2017.515%200%200%200%20.332%204.647%2017.385%2017.385%200%200%200%205.268%200ZM9.772%2017.119a18.963%2018.963%200%200%200%204.456%200A17.182%2017.182%200%200%201%2012%2021.724a17.18%2017.18%200%200%201-2.228-4.605ZM7.777%2015.23a18.87%2018.87%200%200%201-.214-4.774%2012.753%2012.753%200%200%201-4.34-2.708%209.711%209.711%200%200%200-.944%205.004%2017.165%2017.165%200%200%200%205.498%202.477ZM21.356%2014.752a9.765%209.765%200%200%201-7.478%206.817%2018.64%2018.64%200%200%200%201.988-4.718%2018.627%2018.627%200%200%200%205.49-2.098ZM2.644%2014.752c1.682.971%203.53%201.688%205.49%202.099a18.64%2018.64%200%200%200%201.988%204.718%209.765%209.765%200%200%201-7.478-6.816ZM13.878%202.43a9.755%209.755%200%200%201%206.116%203.986%2011.267%2011.267%200%200%201-3.746%202.504%2018.63%2018.63%200%200%200-2.37-6.49ZM12%202.276a17.152%2017.152%200%200%201%202.805%207.121c-.897.23-1.837.353-2.805.353-.968%200-1.908-.122-2.805-.353A17.151%2017.151%200%200%201%2012%202.276ZM10.122%202.43a18.629%2018.629%200%200%200-2.37%206.49%2011.266%2011.266%200%200%201-3.746-2.504%209.754%209.754%200%200%201%206.116-3.985Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.calendar {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M6.75%202.994v2.25m10.5-2.25v2.25m-14.252%2013.5V7.491a2.25%202.25%200%200%201%202.25-2.25h13.5a2.25%202.25%200%200%201%202.25%202.25v11.251m-18%200a2.25%202.25%200%200%200%202.25%202.25h13.5a2.25%202.25%200%200%200%202.25-2.25m-18%200v-7.5a2.25%202.25%200%200%201%202.25-2.25h13.5a2.25%202.25%200%200%201%202.25%202.25v7.5m-6.75-6h2.25m-9%202.25h4.5m.002-2.25h.005v.006H12v-.006Zm-.001%204.5h.006v.006h-.006v-.005Zm-2.25.001h.005v.006H9.75v-.006Zm-2.25%200h.005v.005h-.006v-.005Zm6.75-2.247h.005v.005h-.005v-.005Zm0%202.247h.006v.006h-.006v-.006Zm2.25-2.248h.006V15H16.5v-.005Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M6.75%202.994v2.25m10.5-2.25v2.25m-14.252%2013.5V7.491a2.25%202.25%200%200%201%202.25-2.25h13.5a2.25%202.25%200%200%201%202.25%202.25v11.251m-18%200a2.25%202.25%200%200%200%202.25%202.25h13.5a2.25%202.25%200%200%200%202.25-2.25m-18%200v-7.5a2.25%202.25%200%200%201%202.25-2.25h13.5a2.25%202.25%200%200%201%202.25%202.25v7.5m-6.75-6h2.25m-9%202.25h4.5m.002-2.25h.005v.006H12v-.006Zm-.001%204.5h.006v.006h-.006v-.005Zm-2.25.001h.005v.006H9.75v-.006Zm-2.25%200h.005v.005h-.006v-.005Zm6.75-2.247h.005v.005h-.005v-.005Zm0%202.247h.006v.006h-.006v-.006Zm2.25-2.248h.006V15H16.5v-.005Z%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.calendar:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20d%3D%22M12%2011.993a.75.75%200%200%200-.75.75v.006c0%20.414.336.75.75.75h.006a.75.75%200%200%200%20.75-.75v-.006a.75.75%200%200%200-.75-.75H12ZM12%2016.494a.75.75%200%200%200-.75.75v.005c0%20.414.335.75.75.75h.005a.75.75%200%200%200%20.75-.75v-.005a.75.75%200%200%200-.75-.75H12ZM8.999%2017.244a.75.75%200%200%201%20.75-.75h.006a.75.75%200%200%201%20.75.75v.006a.75.75%200%200%201-.75.75h-.006a.75.75%200%200%201-.75-.75v-.006ZM7.499%2016.494a.75.75%200%200%200-.75.75v.005c0%20.414.336.75.75.75h.005a.75.75%200%200%200%20.75-.75v-.005a.75.75%200%200%200-.75-.75H7.5ZM13.499%2014.997a.75.75%200%200%201%20.75-.75h.006a.75.75%200%200%201%20.75.75v.005a.75.75%200%200%201-.75.75h-.006a.75.75%200%200%201-.75-.75v-.005ZM14.25%2016.494a.75.75%200%200%200-.75.75v.006c0%20.414.335.75.75.75h.005a.75.75%200%200%200%20.75-.75v-.006a.75.75%200%200%200-.75-.75h-.005ZM15.75%2014.995a.75.75%200%200%201%20.75-.75h.005a.75.75%200%200%201%20.75.75v.006a.75.75%200%200%201-.75.75H16.5a.75.75%200%200%201-.75-.75v-.006ZM13.498%2012.743a.75.75%200%200%201%20.75-.75h2.25a.75.75%200%201%201%200%201.5h-2.25a.75.75%200%200%201-.75-.75ZM6.748%2014.993a.75.75%200%200%201%20.75-.75h4.5a.75.75%200%200%201%200%201.5h-4.5a.75.75%200%200%201-.75-.75Z%22%20%2F%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M18%202.993a.75.75%200%200%200-1.5%200v1.5h-9V2.994a.75.75%200%201%200-1.5%200v1.497h-.752a3%203%200%200%200-3%203v11.252a3%203%200%200%200%203%203h13.5a3%203%200%200%200%203-3V7.492a3%203%200%200%200-3-3H18V2.993ZM3.748%2018.743v-7.5a1.5%201.5%200%200%201%201.5-1.5h13.5a1.5%201.5%200%200%201%201.5%201.5v7.5a1.5%201.5%200%200%201-1.5%201.5h-13.5a1.5%201.5%200%200%201-1.5-1.5Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%20class%3D%22size-6%22%3E%0A%20%20%3Cpath%20d%3D%22M12%2011.993a.75.75%200%200%200-.75.75v.006c0%20.414.336.75.75.75h.006a.75.75%200%200%200%20.75-.75v-.006a.75.75%200%200%200-.75-.75H12ZM12%2016.494a.75.75%200%200%200-.75.75v.005c0%20.414.335.75.75.75h.005a.75.75%200%200%200%20.75-.75v-.005a.75.75%200%200%200-.75-.75H12ZM8.999%2017.244a.75.75%200%200%201%20.75-.75h.006a.75.75%200%200%201%20.75.75v.006a.75.75%200%200%201-.75.75h-.006a.75.75%200%200%201-.75-.75v-.006ZM7.499%2016.494a.75.75%200%200%200-.75.75v.005c0%20.414.336.75.75.75h.005a.75.75%200%200%200%20.75-.75v-.005a.75.75%200%200%200-.75-.75H7.5ZM13.499%2014.997a.75.75%200%200%201%20.75-.75h.006a.75.75%200%200%201%20.75.75v.005a.75.75%200%200%201-.75.75h-.006a.75.75%200%200%201-.75-.75v-.005ZM14.25%2016.494a.75.75%200%200%200-.75.75v.006c0%20.414.335.75.75.75h.005a.75.75%200%200%200%20.75-.75v-.006a.75.75%200%200%200-.75-.75h-.005ZM15.75%2014.995a.75.75%200%200%201%20.75-.75h.005a.75.75%200%200%201%20.75.75v.006a.75.75%200%200%201-.75.75H16.5a.75.75%200%200%201-.75-.75v-.006ZM13.498%2012.743a.75.75%200%200%201%20.75-.75h2.25a.75.75%200%201%201%200%201.5h-2.25a.75.75%200%200%201-.75-.75ZM6.748%2014.993a.75.75%200%200%201%20.75-.75h4.5a.75.75%200%200%201%200%201.5h-4.5a.75.75%200%200%201-.75-.75Z%22%20%2F%3E%0A%20%20%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M18%202.993a.75.75%200%200%200-1.5%200v1.5h-9V2.994a.75.75%200%201%200-1.5%200v1.497h-.752a3%203%200%200%200-3%203v11.252a3%203%200%200%200%203%203h13.5a3%203%200%200%200%203-3V7.492a3%203%200%200%200-3-3H18V2.993ZM3.748%2018.743v-7.5a1.5%201.5%200%200%201%201.5-1.5h13.5a1.5%201.5%200%200%201%201.5%201.5v7.5a1.5%201.5%200%200%201-1.5%201.5h-13.5a1.5%201.5%200%200%201-1.5-1.5Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%0A%3C%2Fsvg%3E");
}

.ti-icon.schedule {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%3E%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M12%206v6h4.5m4.5%200a9%209%200%201%201-18%200%209%209%200%200%201%2018%200Z%22%20%2F%3E%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20fill%3D%22none%22%20viewBox%3D%220%200%2024%2024%22%20stroke-width%3D%221.5%22%20stroke%3D%22currentColor%22%3E%3Cpath%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22M12%206v6h4.5m4.5%200a9%209%200%201%201-18%200%209%209%200%200%201%2018%200Z%22%20%2F%3E%3C%2Fsvg%3E");
}

.ti-icon.schedule:hover {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M12%202.25c-5.385%200-9.75%204.365-9.75%209.75s4.365%209.75%209.75%209.75%209.75-4.365%209.75-9.75S17.385%202.25%2012%202.25ZM12.75%206a.75.75%200%200%200-1.5%200v6c0%20.414.336.75.75.75h4.5a.75.75%200%200%200%200-1.5h-3.75V6Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%3C%2Fsvg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22currentColor%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M12%202.25c-5.385%200-9.75%204.365-9.75%209.75s4.365%209.75%209.75%209.75%209.75-4.365%209.75-9.75S17.385%202.25%2012%202.25ZM12.75%206a.75.75%200%200%200-1.5%200v6c0%20.414.336.75.75.75h4.5a.75.75%200%200%200%200-1.5h-3.75V6Z%22%20clip-rule%3D%22evenodd%22%20%2F%3E%3C%2Fsvg%3E");
}

/* ============================================================
   Inline icons — small lucide-style stroked glyphs extracted
   from the screens. All inherit colour via currentColor and
   size via the .xs/.sm/.md/.lg/.xl modifiers on .ti-icon.
   Group A: actions (plus, close, check, send, search)
   Group B: status / signals (clock, hourglass, warning-triangle,
            info, check-circle, bell)
   Group C: nouns (calendar-blank, user, users, briefcase,
            book, folder, help-circle)
   Group D: layout / navigation (chevron-left, chevron-right,
            dashboard-grid, cycles-loop, sun, theme-toggle)
   ============================================================ */

.ti-icon.plus {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E");
}

.ti-icon.menu {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7h16M4 12h16M4 17h16'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7h16M4 12h16M4 17h16'/%3E%3C/svg%3E");
}

.ti-icon.close {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6L6 18M6 6l12 12'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6L6 18M6 6l12 12'/%3E%3C/svg%3E");
}

.ti-icon.check {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
}

/* Check inside a clipboard — used as the "evaluation" affordance on rows / panels. */
.ti-icon.check-clipboard {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 11l3 3L22 4'/%3E%3Cpath d='M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 11l3 3L22 4'/%3E%3Cpath d='M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11'/%3E%3C/svg%3E");
}

/* Right-pointing solid triangle — open / submit / play. */
.ti-icon.send {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor' stroke='currentColor' stroke-width='1' stroke-linejoin='round'%3E%3Cpolygon points='5 3 19 12 5 21 5 3'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor' stroke='currentColor' stroke-width='1' stroke-linejoin='round'%3E%3Cpolygon points='5 3 19 12 5 21 5 3'/%3E%3C/svg%3E");
}

.ti-icon.search {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E");
}

.ti-icon.clock {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E");
}

/* The hourglass the empty grade chip draws for "still to come", as an icon: the busy indicator turns it (CA-345). */
.ti-icon.hourglass {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 22h14'/%3E%3Cpath d='M5 2h14'/%3E%3Cpath d='M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22'/%3E%3Cpath d='M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 22h14'/%3E%3Cpath d='M5 2h14'/%3E%3Cpath d='M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22'/%3E%3Cpath d='M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2'/%3E%3C/svg%3E");
}

.ti-icon.warning-triangle {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'/%3E%3Cline x1='12' y1='9' x2='12' y2='13'/%3E%3Cline x1='12' y1='17' x2='12.01' y2='17'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'/%3E%3Cline x1='12' y1='9' x2='12' y2='13'/%3E%3Cline x1='12' y1='17' x2='12.01' y2='17'/%3E%3C/svg%3E");
}

.ti-icon.info-circle {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='16' x2='12' y2='12'/%3E%3Cline x1='12' y1='8' x2='12.01' y2='8'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='16' x2='12' y2='12'/%3E%3Cline x1='12' y1='8' x2='12.01' y2='8'/%3E%3C/svg%3E");
}

.ti-icon.bell {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9'/%3E%3Cpath d='M13.73 21a2 2 0 0 1-3.46 0'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9'/%3E%3Cpath d='M13.73 21a2 2 0 0 1-3.46 0'/%3E%3C/svg%3E");
}

/* Simple Feather-style calendar — used by deadline cards / period columns / date inputs. */
.ti-icon.calendar-blank {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
}

.ti-icon.user {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='12' cy='7' r='4'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='12' cy='7' r='4'/%3E%3C/svg%3E");
}

.ti-icon.users {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E");
}

.ti-icon.briefcase {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='7' width='20' height='14' rx='2'/%3E%3Cpath d='M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='7' width='20' height='14' rx='2'/%3E%3Cpath d='M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2'/%3E%3C/svg%3E");
}

.ti-icon.folder {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z'/%3E%3C/svg%3E");
}

.ti-icon.book {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z'/%3E%3Cpath d='M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z'/%3E%3Cpath d='M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z'/%3E%3C/svg%3E");
}

.ti-icon.help-circle {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'/%3E%3Cline x1='12' y1='17' x2='12.01' y2='17'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'/%3E%3Cline x1='12' y1='17' x2='12.01' y2='17'/%3E%3C/svg%3E");
}

.ti-icon.chevron-left {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='15 18 9 12 15 6'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='15 18 9 12 15 6'/%3E%3C/svg%3E");
}

.ti-icon.chevron-right {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 18 15 12 9 6'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 18 15 12 9 6'/%3E%3C/svg%3E");
}

/* Four small rounded squares — sidebar Dashboard nav entry. */
.ti-icon.dashboard-grid {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1.5'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1.5'/%3E%3C/svg%3E");
}

/* Circular arrow with a small arrowhead — sidebar Cycles nav entry. */
.ti-icon.cycles-loop {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12a9 9 0 1 1-3-6.7'/%3E%3Cpolyline points='21 4 21 10 15 10'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12a9 9 0 1 1-3-6.7'/%3E%3Cpolyline points='21 4 21 10 15 10'/%3E%3C/svg%3E");
}

.ti-icon.sun {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='5'/%3E%3Cline x1='12' y1='1' x2='12' y2='3'/%3E%3Cline x1='12' y1='21' x2='12' y2='23'/%3E%3Cline x1='4.22' y1='4.22' x2='5.64' y2='5.64'/%3E%3Cline x1='18.36' y1='18.36' x2='19.78' y2='19.78'/%3E%3Cline x1='1' y1='12' x2='3' y2='12'/%3E%3Cline x1='21' y1='12' x2='23' y2='12'/%3E%3Cline x1='4.22' y1='19.78' x2='5.64' y2='18.36'/%3E%3Cline x1='18.36' y1='5.64' x2='19.78' y2='4.22'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='5'/%3E%3Cline x1='12' y1='1' x2='12' y2='3'/%3E%3Cline x1='12' y1='21' x2='12' y2='23'/%3E%3Cline x1='4.22' y1='4.22' x2='5.64' y2='5.64'/%3E%3Cline x1='18.36' y1='18.36' x2='19.78' y2='19.78'/%3E%3Cline x1='1' y1='12' x2='3' y2='12'/%3E%3Cline x1='21' y1='12' x2='23' y2='12'/%3E%3Cline x1='4.22' y1='19.78' x2='5.64' y2='18.36'/%3E%3Cline x1='18.36' y1='5.64' x2='19.78' y2='4.22'/%3E%3C/svg%3E");
}

.ti-icon.moon {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z'/%3E%3C/svg%3E");
}

.ti-icon.eye {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
}

/* Check inside a circle — Ready / completed indicator. */
.ti-icon.check-circle {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 11.08V12a10 10 0 1 1-5.93-9.14'/%3E%3Cpolyline points='22 4 12 14.01 9 11.01'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 11.08V12a10 10 0 1 1-5.93-9.14'/%3E%3Cpolyline points='22 4 12 14.01 9 11.01'/%3E%3C/svg%3E");
}

/* Three vertical bars of varying height — column / bar chart. */
.ti-icon.bar-chart {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='20' x2='18' y2='10'/%3E%3Cline x1='12' y1='20' x2='12' y2='4'/%3E%3Cline x1='6' y1='20' x2='6' y2='14'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='20' x2='18' y2='10'/%3E%3Cline x1='12' y1='20' x2='12' y2='4'/%3E%3Cline x1='6' y1='20' x2='6' y2='14'/%3E%3C/svg%3E");
}

.ti-main {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-height: 100vh;
    overflow: hidden;
}

.ti-sidebar {
    display: flex;
    flex-flow: column;
    justify-content: space-between;
    flex: auto;
    z-index: 1000;
}


.ti-sidebar-button {
    width: var(--ti-button-size);
    height: var(--ti-button-size);
    border-radius: var(--ti-button-radius);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    text-decoration: none;
}

.ti-sidebar-button:link {
    text-decoration: none !important;
}

.ti-sidebar-button:visited {
    text-decoration: none !important;
}

.ti-content {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: auto;
    width: 100%;
    height: 100%;
    min-height: 0;
}

.ti-content.pane {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: var(--ti-gap);
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    padding: var(--ti-padding);
    overflow: auto;
    overscroll-behavior: none;
}


.ti-notifications {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + var(--ti-notification-top));
    left: 0;
    right: 0;
    box-sizing: border-box;
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    display: flex;
    align-items: center;
    justify-content: center;
    flex: auto;
    width: auto;
    z-index: 1100;
    pointer-events: none;
}

.ti-notification {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-direction: row;
    gap: var(--ti-gap);
    cursor: pointer;
    pointer-events: auto;
    padding: var(--ti-padding);
    border-radius: 12px;
    max-width: 60%;
    width: fit-content; /* Ensures the container shrinks to fit ti-content if text is short */
    margin-left: auto; /* Centers the container if it has relative positioning */
    margin-right: auto;
}

.ti-notification:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 2px;
}

/* Flyout (popover) menu styling */
.ti-sidebar-flyout-container {
    display: inline-flex;
    position: relative;
    width: 100%;
}

.ti-sidebar-flyout[hidden] {
    display: none !important;
}

.ti-sidebar-flyout {
    /* Positioning */
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1001;
    transform: none;

    /* Box model */
    min-width: 220px;
    padding: var(--s-2);
    margin-left: 20px;
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);

    /* Layout */
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ti-application.collapsed .ti-sidebar-flyout {
    margin-left: 16px;
}

/* Flyout items */
.ti-sidebar-flyout-item {
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    cursor: pointer;
    gap: var(--s-3);
    font-family: inherit;
    font-size: var(--fs-base);
    font-weight: 500;
    -webkit-tap-highlight-color: transparent;
    appearance: none;
    width: 100%;
    box-sizing: border-box;
    border: 0;
    background: transparent;
    color: var(--fg-primary);
    text-align: left;
    padding: var(--s-2) var(--s-3);
    border-radius: var(--r-md);
    transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}

.ti-sidebar-flyout-item .ti-icon {
    width: 18px;
    height: 18px;
    background-color: var(--fg-secondary);
    flex-shrink: 0;
}

.ti-sidebar-flyout-item:hover {
    background: var(--bg-tint);
}

.ti-sidebar-flyout-item:hover .ti-icon {
    background-color: var(--fg-primary);
}

.ti-sidebar-flyout-item:active {
    background: var(--bg-sunken);
}

.ti-sidebar-flyout-item:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}


.ti-tooltip {
    position: relative;
    display: inline-block;
}

.ti-tooltip-bubble {
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    margin-bottom: var(--ti-tooltip-gap, 8px);
    padding: var(--ti-tooltip-padding, 6px 12px);
    background-color: var(--ti-tooltip-bg-color, rgba(0, 0, 0, 0.85));
    color: var(--ti-tooltip-fg-color, white);
    font-size: var(--ti-tooltip-font-size, 0.875rem);
    line-height: var(--ti-tooltip-line-height, 1.4);
    border-radius: var(--ti-tooltip-border-radius, 4px);
    width: max-content;
    max-width: var(--ti-tooltip-max-width, min(80vw, 320px));
    white-space: normal;
    overflow-wrap: break-word;
    box-shadow: var(--ti-tooltip-shadow, none);
    z-index: 1005;
    pointer-events: none;
}

.ti-tooltip-bubble::before {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: var(--ti-tooltip-arrow-size, 5px) solid transparent;
    border-top-color: var(--ti-tooltip-bg-color, rgba(0, 0, 0, 0.85));
}

/* Mobile devices (tablets and phones) */
@media screen and (width <= 720px) {
    .ti-notification {
        max-width: 90%; /* Allows more space on smaller screens */
        width: 90%; /* Ensures consistent width on very small screens */
    }
}

/* ============================================================
   Design System v2 — Shared tokens (theme-agnostic)
   Theme-specific values live in ti-theme-daylight.css and
   ti-theme-black-glass.css, keyed by [data-theme] attribute.
   ============================================================ */

:root {
    /* Type scale */
    --fs-xxs: 10px;
    --fs-xs: 11px;
    --fs-sm: 12px;
    --fs-base: 13.5px;
    --fs-md: 15px;
    --fs-lg: 18px;
    --fs-xl: 22px;
    --fs-2xl: 28px;
    --fs-3xl: 36px;
    --fs-display: 48px;

    /* Spacing */
    --s-1: 4px;
    --s-2: 8px;
    --s-3: 12px;
    --s-4: 16px;
    --s-5: 20px;
    --s-6: 24px;
    --s-7: 32px;
    --s-8: 40px;
    --s-9: 56px;
    --s-10: 72px;

    /* Radius */
    --r-xs: 4px;
    --r-sm: 6px;
    --r-md: 10px;
    --r-lg: 14px;
    --r-xl: 20px;
    --r-pill: 999px;

    /* Layout */
    --sidebar-w: 220px;
    --sidebar-w-collapsed: 64px;
    --header-h: 64px;
    --content-max: 1180px;

    /* Animation */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    --dur-fast: 140ms;
    --dur-base: 220ms;
    --dur-slow: 380ms;
}

/* ============================================================
   App shell — CSS grid with collapsible ti-sidebar
   ============================================================ */
.ti-application {
    display: grid;
    grid-template-columns: var(--sidebar-w) 1fr;
    height: 100vh;
    background: var(--bg-app);
    transition: grid-template-columns var(--dur-base) var(--ease-out);
}

.ti-application.collapsed {
    grid-template-columns: var(--sidebar-w-collapsed) 1fr;
}

/* ============================================================
   Sidebar
   ============================================================ */
.ti-sidebar {
    background: var(--sidebar-bg);
    color: var(--sidebar-fg);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    border-right: 1px solid var(--sidebar-divider);
    /*
     * The sidebar scrolls its own overflow. It used to be `overflow: hidden`, which silently ate every
     * entry past the fold: a consuming application appends its own sections as direct children, and once
     * those exceed 100vh there was nowhere for the excess to go and no way for a visitor to reach it.
     * Measured with competence's 21 entries at 1440x800 — 1094px of content in an 800px box, and a mouse
     * wheel over the sidebar moved it 0px. What went under the fold included `.ti-sidebar-foot`, which
     * carries the theme toggle and the user menu, and the user menu is where sign-out lives.
     *
     * The vertical padding this rule used to carry moved onto `.ti-sidebar-brand` and `.ti-sidebar-foot`.
     * Left here it sits inside the scrollport, and the list scrolls visibly through the gap above the
     * pinned brand and below the pinned footer.
     *
     * `overflow-x` must stay hidden rather than visible: declaring a scroller on one axis forces the other
     * to compute to a non-visible value anyway, and the collapse button has always been clipped by this.
     */
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: none;
    scrollbar-width: thin;
    scrollbar-color: var(--sidebar-divider) transparent;
}

.ti-sidebar::-webkit-scrollbar {
    width: 10px;
}

.ti-sidebar::-webkit-scrollbar-track {
    background: transparent;
}

.ti-sidebar::-webkit-scrollbar-thumb {
    background-color: var(--sidebar-divider);
    border-radius: 5px;
    /* Drawn inside a transparent border so the thumb reads as a 4px hairline against the sidebar. */
    border: 3px solid transparent;
    background-clip: content-box;
}

.ti-sidebar:hover::-webkit-scrollbar-thumb {
    background-color: var(--sidebar-fg);
}

/*
 * Nothing in the column shrinks. Every other child is floored by a `min-height`, but
 * `.ti-sidebar-section-label` is not, so under the old clipping layout it absorbed the entire shrink and
 * cut its own text in half — 25px down to 14px, which is what made "QUICK LINKS" unreadable in the report
 * while the entries above it looked fine. This has to match every child rather than the label alone,
 * because the children belong to the consuming application, not to the framework.
 */
.ti-sidebar > * {
    flex-shrink: 0;
}

.ti-sidebar-collapse-btn {
    /*
     * Sticky rather than absolute: an absolutely positioned child of a scroll container scrolls with the
     * content, so the button would slide out of view as soon as the list moved. `align-self` plus the
     * negative margin reproduce what `right: -12px` did, and the negative bottom margin keeps it out of
     * the flow so it does not push the brand down.
     */
    position: sticky;
    top: 20px;
    align-self: flex-end;
    margin-right: -12px;
    margin-bottom: -22px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--bg-surface);
    color: var(--fg-secondary);
    display: grid;
    place-items: center;
    cursor: pointer;
    z-index: 11;
    box-shadow: var(--shadow-sm);
    opacity: 0;
    transform: translateX(-4px);
    transition: opacity var(--dur-fast), transform var(--dur-fast), background var(--dur-fast);
}

.ti-application:hover .ti-sidebar-collapse-btn,
.ti-sidebar-collapse-btn:focus-visible {
    opacity: 1;
    transform: translateX(0);
}

.ti-sidebar-collapse-btn:hover {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
}

.ti-application.collapsed .ti-sidebar-collapse-btn svg {
    transform: rotate(180deg);
}

.ti-sidebar-collapse-btn svg {
    transition: transform var(--dur-base) var(--ease-out);
}

.ti-sidebar-brand {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    /* The leading `calc` absorbs the padding-top `.ti-sidebar` used to carry — see the note there. */
    padding: calc(var(--s-3) * 2) var(--s-4) var(--s-4);
    color: var(--sidebar-fg-active);
    white-space: nowrap;
    min-height: 56px;
    position: sticky;
    top: 0;
    z-index: 2;
    /*
     * `--sidebar-bg` is translucent in the glass theme (rgba(10, 12, 17, 0.78)), so painting the pinned
     * rows with it alone would let the scrolling list show through them. Compositing it over `--bg-app`
     * reproduces the sidebar's own rendered colour exactly while being fully opaque, and is a no-op for a
     * theme whose `--sidebar-bg` is already solid.
     */
    background: linear-gradient(var(--sidebar-bg), var(--sidebar-bg)), var(--bg-app);
}

.ti-application.collapsed .ti-sidebar-brand {
    padding-left: 16px;
    padding-right: 16px;
}

.ti-application.collapsed .ti-sidebar-brand-text-block {
    opacity: 0;
    pointer-events: none;
}

.ti-sidebar-brand-text-block {
    display: flex;
    flex-direction: column;
    min-width: 0;
    transition: opacity var(--dur-fast);
}

.ti-sidebar-brand-mark {
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    border-radius: 8px;
    background: linear-gradient(135deg, var(--accent), color-mix(in oklab, var(--accent) 70%, #000));
    color: #FFF;
    font-weight: 700;
    font-size: 14px;
    letter-spacing: -0.02em;
    box-shadow: 0 4px 12px color-mix(in oklab, var(--accent) 32%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.25);
    flex: 0 0 auto;
}

.ti-sidebar-brand-text {
    font-weight: 600;
    font-size: 15px;
    letter-spacing: -0.01em;
}

.ti-sidebar-brand-sub {
    font-size: 11px;
    color: var(--sidebar-fg);
    font-weight: 400;
}

.ti-sidebar-section-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--sidebar-fg);
    opacity: 0.5;
    padding: var(--s-2) var(--s-4) 6px;
    margin-top: var(--s-3);
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    transition: opacity var(--dur-fast), padding var(--dur-fast);
}

.ti-application.collapsed .ti-sidebar-section-label {
    font-size: 0;
    padding-top: var(--s-3);
    padding-bottom: 0;
    margin-top: 0;
    height: 8px;
    position: relative;
}

.ti-application.collapsed .ti-sidebar-section-label::after {
    content: "";
    position: absolute;
    left: 18px;
    right: 18px;
    top: 50%;
    height: 1px;
    background: var(--sidebar-divider);
}

.ti-sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0 var(--s-3);
}

.ti-sidebar-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding: 8px 10px;
    border-radius: 8px;
    color: var(--sidebar-fg);
    background: transparent;
    border: 0;
    text-align: left;
    font-size: var(--fs-base);
    font-family: inherit;
    font-weight: 500;
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
    width: 100%;
    white-space: nowrap;
    min-height: 36px;
    text-decoration: none;
}

.ti-sidebar-item-label {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: opacity var(--dur-fast);
}

.ti-application.collapsed .ti-sidebar-item-label {
    opacity: 0;
    pointer-events: none;
    flex: 0 0 0;
    max-width: 0;
    margin: 0;
    overflow: hidden;
}

.ti-application.collapsed .ti-sidebar-nav {
    padding-left: var(--s-2);
    padding-right: var(--s-2);
}

.ti-application.collapsed .ti-sidebar-foot {
    padding-left: var(--s-2);
    padding-right: var(--s-2);
}

.ti-application.collapsed .ti-sidebar-item {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
    gap: 0;
}

.ti-application.collapsed .ti-sidebar-item .ti-sidebar-item-icon {
    margin: 0;
}

/* Collapsed tooltip */
.ti-application.collapsed .ti-sidebar-item:hover::after,
.ti-application.collapsed .ti-sidebar-user:hover::after {
    content: attr(data-tip);
    position: absolute;
    left: calc(100% + 12px);
    top: 50%;
    transform: translateY(-50%);
    background: var(--fg-primary);
    color: var(--bg-surface);
    font-size: 12px;
    font-weight: 500;
    padding: 5px 10px;
    border-radius: 6px;
    white-space: nowrap;
    z-index: 50;
    pointer-events: none;
    box-shadow: var(--shadow-md);
}

.ti-sidebar-item:hover {
    background: var(--sidebar-hover-bg);
    color: var(--sidebar-fg-active);
}

.ti-sidebar-item.active {
    background: var(--sidebar-active-bg);
    color: var(--sidebar-fg-active);
}

.ti-sidebar-item.active::before {
    content: "";
    position: absolute;
    left: calc(-1 * var(--s-3));
    top: 8px;
    bottom: 8px;
    width: 3px;
    border-radius: 3px;
    background: var(--sidebar-accent);
}

.ti-application.collapsed .ti-sidebar-item.active::before {
    left: calc(-1 * var(--s-2));
}

.ti-sidebar-item:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

.ti-sidebar-item-icon {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    opacity: 0.85;
}

.ti-sidebar-item.active .ti-sidebar-item-icon {
    opacity: 1;
}


.ti-sidebar-foot {
    /* `margin-top: auto` still pushes the footer down when the list is short enough to fit; when it is
       not, there is no free space to distribute and `sticky` is what keeps the footer on screen. */
    margin-top: auto;
    /* The trailing value absorbs the padding-bottom `.ti-sidebar` used to carry — see the note there. */
    padding: var(--s-2) var(--s-3) var(--s-3);
    display: flex;
    flex-direction: column;
    gap: 2px;
    border-top: 1px solid var(--sidebar-divider);
    position: sticky;
    bottom: 0;
    z-index: 2;
    background: linear-gradient(var(--sidebar-bg), var(--sidebar-bg)), var(--bg-app);
}

.ti-sidebar-user {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding: 8px 10px;
    border-radius: 10px;
    cursor: pointer;
    border: 0;
    background: transparent;
    color: var(--sidebar-fg);
    text-align: left;
    width: 100%;
    white-space: nowrap;
    min-height: 44px;
    position: relative;
}

.ti-application.collapsed .ti-sidebar-user {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
    gap: 0;
}

.ti-application.collapsed .ti-sidebar-user-text {
    display: none;
    opacity: 0;
    pointer-events: none;
}

.ti-sidebar-user-text {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
    transition: opacity var(--dur-fast);
}

.ti-sidebar-user:hover {
    background: var(--sidebar-hover-bg);
}

.ti-sidebar-user-name {
    font-weight: 600;
    font-size: 13px;
    color: var(--sidebar-fg-active);
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Keep the role/department line to a single, ellipsised line — names like "Project & Delivery Management" would
   otherwise overflow the fixed-width sidebar. */
.ti-sidebar-user-sub {
    font-size: 11px;
    opacity: 0.7;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ============================================================
   Content area & ti-topbar
   ============================================================ */
.ti-content {
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow: hidden;
}

.ti-topbar {
    height: var(--header-h);
    width: 100%;
    display: flex;
    align-items: center;
    gap: var(--s-4);
    padding: 0 var(--s-7);
    border-bottom: 1px solid var(--border);
    background: var(--bg-surface);
    position: sticky;
    top: 0;
    z-index: 10;
    flex: 0 0 auto;
}

.ti-topbar-title {
    font-size: var(--fs-lg);
    font-weight: 600;
    letter-spacing: -0.015em;
    color: var(--fg-primary);
    white-space: nowrap;
}

.ti-topbar-sub {
    color: var(--fg-tertiary);
    font-size: var(--fs-sm);
    margin-left: var(--s-3);
    padding-left: var(--s-3);
    border-left: 1px solid var(--border);
    white-space: nowrap;
}

#ti-topbar-info {
    display: flex;
    align-items: center;
    gap: var(--s-3);
}

.ti-topbar-spacer {
    flex: 1;
}

.ti-topbar-actions {
    display: flex;
    align-items: center;
    gap: var(--s-3);
}

/* ============================================================
   Busy state (CA-345)
   ============================================================ */

/* While the shell waits on a request past its delay (`tiApplication.busy`), every element shows the progress cursor:
   the application is working, and still takes input. `!important` because the element under the pointer is nearly
   always the button just clicked, and buttons, links and inputs set cursors of their own. */
html.ti-busy,
html.ti-busy * {
    cursor: progress !important;
}

/* The slot keeps its size while idle, so nothing beside it moves when the hourglass appears. Sized and coloured as
   the ghost icon buttons a topbar puts next to it. */
.ti-busy-indicator {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex: 0 0 auto;
    color: var(--fg-secondary);
}

.ti-busy-indicator-glyph {
    opacity: 0;
    transition: opacity 160ms ease;
}

html.ti-busy .ti-busy-indicator-glyph {
    opacity: 1;
    animation: busyTurn 2s ease-in-out infinite;
}

/* An hourglass is turned over, not spun: it rests, then makes half a turn, twice a cycle. */
@keyframes busyTurn {
    0%, 35% {
        transform: rotate(0deg);
    }
    50%, 85% {
        transform: rotate(180deg);
    }
    100% {
        transform: rotate(360deg);
    }
}

/* Reduced motion keeps the hourglass and the cursor, still. */
@media (prefers-reduced-motion: reduce) {
    .ti-busy-indicator-glyph {
        transition: none;
    }

    html.ti-busy .ti-busy-indicator-glyph {
        animation: none;
    }
}

/* Text for assistive technology alone, such as the line a status region announces. Never `display: none`, which
   takes it out of the accessibility tree as well. */
.ti-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ============================================================
   Narrow screens — the sidebar as a drawer (CA-406)
   ============================================================ */

/*
 * The shell's two columns do not fit a phone: measured at 390x844, a 280px sidebar left the screen 110px. Below 900px
 * the sidebar leaves the grid and slides in over the screen from the menu button the topbar carries.
 *
 * Only a shell whose page holds that button becomes a drawer (`:has()`). An application whose own topbar predates the
 * button keeps the sidebar in its column, cramped but reachable, rather than hidden with nothing to open it.
 *
 * The width is written twice: here, and as NAVIGATION_DRAWER_QUERY in ti-framework.js, which keeps the collapsed
 * state out of the drawer. test/ti-framework.navigation-drawer.test.js holds the two together.
 */
.ti-navigation-toggle-slot {
    display: none;
}

.ti-navigation-scrim {
    display: none;
}

@media (max-width: 900px) {
    .ti-application:has(.ti-navigation-toggle) {
        grid-template-columns: minmax(0, 1fr);
        /* The dynamic viewport. On a phone `100vh` is the height with the browser's toolbar retracted, so while the
           toolbar shows, the bottom of every screen sits under it. */
        height: 100dvh;
    }

    .ti-application:has(.ti-navigation-toggle) .ti-sidebar {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 1110;
        /* Never the whole width: the strip of screen left beside it is what says it is a drawer over the page. */
        width: min(var(--sidebar-w), calc(100vw - 56px));
        height: auto;
        transform: translateX(-100%);
        /* Hidden as well as moved, so that while it is shut its entries are out of the tab order and the accessibility
           tree. The delay keeps it visible until it has slid out. */
        visibility: hidden;
        transition: transform var(--dur-base) var(--ease-out), visibility 0s linear var(--dur-base);
    }

    /* `transform: none` rather than a zero translation: any transform makes the drawer the containing block of its
       fixed descendants, and the user menu's flyout is one, placed against the viewport. */
    html.ti-navigation-open .ti-application:has(.ti-navigation-toggle) .ti-sidebar {
        transform: none;
        visibility: visible;
        transition: transform var(--dur-base) var(--ease-out), visibility 0s;
        box-shadow: var(--shadow-lg);
    }

    /* The drawer is open or shut. Collapsing to icons belongs to the column. */
    .ti-application:has(.ti-navigation-toggle) .ti-sidebar-collapse-btn {
        display: none;
    }

    .ti-navigation-toggle-slot {
        display: inline-flex;
        flex: 0 0 auto;
    }

    html.ti-navigation-open .ti-navigation-scrim {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 1105;
        background: rgba(0, 0, 0, 0.45);
        /* A drag on the scrim must not scroll the screen under it. */
        touch-action: none;
    }

    .ti-application:has(.ti-navigation-toggle) .ti-topbar {
        gap: var(--s-3);
        padding: 0 var(--s-4);
    }

    /* The screen's name gives way before the buttons beside it, so that a screen's own action in the topbar stays on
       the page: measured at 390px, the title and its subtitle pushed "New cycle" off the edge. The subtitle goes,
       and the title takes an ellipsis when it still runs out of room. Shrinking the two by weight left neither
       readable ("Cycl…" beside "Aut…"), because the subtitle's padding and rule cannot shrink. */
    .ti-application:has(.ti-navigation-toggle) #ti-topbar-info {
        flex: 1 1 auto;
        min-width: 0;
    }

    .ti-application:has(.ti-navigation-toggle) .ti-topbar-title {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .ti-application:has(.ti-navigation-toggle) .ti-topbar-sub {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ti-application:has(.ti-navigation-toggle) .ti-sidebar,
    html.ti-navigation-open .ti-application:has(.ti-navigation-toggle) .ti-sidebar {
        transition: none;
    }
}

.ti-page {
    padding: var(--s-3) var(--s-5) var(--s-5);
    max-width: var(--content-max);
    margin: 0 auto;
    width: 100%;
    box-sizing: border-box;
}


.ti-page-scrollable {
    flex: 1;
    overflow-y: auto;
    overscroll-behavior: none;
    min-height: 0;
    width: 100%;
}

/* Hide OOB elements that land in the ti-content area before HTMX swaps them out */
#ti-content [hx-swap-oob] {
    display: none;
}

/* ============================================================
   Panel & ti-card
   ============================================================ */
.ti-panel, .ti-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-xs);
    overflow: hidden;
}

/* Reusable card grid — a responsive two-column layout of .ti-card blocks; any direct child marked
   .ti-card-wide (or a non-card full-row element like a banner) spans the whole row. Collapses to one
   column on narrow viewports. App-agnostic; first consumed by the competence Insights screens. */
.ti-card-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s-5);
    align-items: start;
}

.ti-card-grid > .ti-card-wide {
    grid-column: 1 / -1;
}

@media ( max-width: 720px ) {
    .ti-card-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* A muted, collapsible note/disclosure within a card (e.g. a "how it's calculated" methodology block). */
.ti-card-note {
    margin-top: var(--s-3);
    font-size: var(--fs-sm);
    color: var(--fg-secondary);
}

.ti-card-note > summary {
    cursor: pointer;
    color: var(--fg-secondary);
    list-style-position: inside;
}

.ti-card-note > p {
    margin: var(--s-2) 0 0;
    line-height: 1.5;
}

.ti-panel-head {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding-bottom: var(--s-3);
    margin-bottom: var(--s-4);
    border-bottom: 1px solid var(--border-soft);
}

/* Banner variant — the head reads as a full-width strip on a panel that does not use the default
   .ti-panel padding (e.g. sectioned cards with internal sub-content beneath the head). */
.ti-panel-head.bar {
    padding: var(--s-4) var(--s-5);
    margin: 0;
    background: var(--bg-sunken);
    border-bottom: 1px solid var(--border-soft);
}

/* Square icon on the left of the head. Sized for a 16-18px stroked SVG. */
.ti-panel-head-icon {
    width: 32px;
    height: 32px;
    border-radius: var(--r-sm);
    background: var(--bg-surface);
    border: 1px solid var(--border);
    color: var(--fg-secondary);
    display: grid;
    place-items: center;
    flex: 0 0 auto;
}

/* Wraps the title + subtitle so they stack while the head itself stays a single flex row. */
.ti-panel-head-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ti-panel-title {
    font-size: var(--fs-md);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--fg-primary);
}

/* Small qualifier inline with the title (e.g. "(optional)"). */
.ti-panel-title-aside {
    font-size: var(--fs-xs);
    font-weight: 500;
    color: var(--fg-tertiary);
    margin-left: var(--s-2);
}

/* Smaller dimmed subtitle line under the title, optionally with an inline icon + meta string. */
.ti-panel-subtitle {
    font-size: var(--fs-sm);
    color: var(--fg-tertiary);
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
}

/* Right-aligned secondary info with a thin separator border on the left. Use for read-only
   informative content (counts, hints, recommended thresholds, etc.). */
.ti-panel-head-aside {
    padding-left: var(--s-3);
    border-left: 1px solid var(--border);
    color: var(--fg-tertiary);
    font-size: var(--fs-sm);
    white-space: nowrap;
    flex: 0 0 auto;
}

.ti-panel-head-aside strong {
    color: var(--fg-primary);
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas, monospace;
    font-weight: 500;
}

/* Right-aligned action buttons (Cancel / Save / + New …). Sits to the right alongside or in place
   of .ti-panel-head-aside. */
.ti-panel-head-actions {
    margin-left: auto;
    display: flex;
    gap: var(--s-2);
    flex: 0 0 auto;
}

/* When both .ti-panel-head-aside and .ti-panel-head-actions appear, only the aside gets the
   auto-margin — the actions sit immediately next to it. */
.ti-panel-head-aside + .ti-panel-head-actions {
    margin-left: 0;
}

.ti-panel-body-intro {
    font-size: var(--fs-sm);
    color: var(--fg-secondary);
    padding: 0 var(--s-3) var(--s-5);
    line-height: 1.5;
}

/* ============================================================
   Buttons
   ============================================================ */
.ti-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    height: 36px;
    padding: 0 14px;
    border-radius: 9px;
    background: var(--bg-surface);
    border: 1px solid var(--border);
    color: var(--fg-primary);
    font-size: var(--fs-base);
    font-family: inherit;
    font-weight: 500;
    letter-spacing: -0.005em;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.ti-btn:hover {
    background: var(--bg-sunken);
    border-color: var(--border-strong);
}

.ti-btn:active {
    transform: translateY(1px);
}

.ti-btn:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
}

.ti-btn[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

.ti-btn.primary {
    background: var(--accent);
    color: var(--fg-on-accent);
    border-color: transparent;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px color-mix(in oklab, var(--accent) 18%, transparent);
}

.ti-btn.primary:hover {
    background: var(--accent-hover);
}

.ti-btn.ghost {
    background: transparent;
    border-color: transparent;
    color: var(--fg-secondary);
}

.ti-btn.ghost:hover {
    background: var(--bg-tint);
    color: var(--fg-primary);
}

.ti-btn.danger {
    background: transparent;
    border-color: var(--border);
    color: var(--danger);
}

.ti-btn.danger:hover {
    background: var(--danger-soft);
    border-color: var(--danger);
}

.ti-btn.lg {
    height: 42px;
    padding: 0 18px;
    font-size: var(--fs-md);
}

.ti-btn.sm {
    height: 28px;
    padding: 0 10px;
    font-size: var(--fs-sm);
    border-radius: 7px;
}

.ti-btn.icon {
    width: 36px;
    padding: 0;
}

.ti-btn.sm.icon {
    width: 28px;
}


/* ============================================================
   Inputs
   ============================================================ */
.ti-input, .ti-select, .ti-textarea {
    width: 100%;
    height: 38px;
    padding: 0 12px;
    border-radius: 8px;
    background: var(--bg-surface);
    border: 1px solid var(--border);
    color: var(--fg-primary);
    font-size: var(--fs-base);
    font-family: inherit;
    outline: none;
    transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
    box-sizing: border-box;
}

.ti-input:hover, .ti-select:hover, .ti-textarea:hover {
    border-color: var(--border-strong);
}

.ti-input:focus, .ti-select:focus, .ti-textarea:focus {
    border-color: var(--accent);
    box-shadow: var(--shadow-focus);
}

.ti-input.has-error, .ti-select.has-error, .ti-textarea.has-error {
    border-color: var(--danger);
    box-shadow: 0 0 0 3px var(--danger-soft);
}

.ti-textarea {
    height: auto;
    padding: 10px 12px;
    resize: vertical;
    min-height: 100px;
    line-height: 1.5;
}

/* Custom chevron for selects.
   The native <select> chevron position is browser-controlled and ends up visually offset from the calendar
   icon that <input type="date"> renders. Disable the native chevron with appearance:none and draw our own
   so both glyphs sit at the same right offset. Padding-right reserves the glyph slot; padding-right on
   the date input matches so the calendar icon's natural right margin lines up with the chevron.
   Theme-specific stroke colour because SVG inside background-image can't pick up currentColor. */
.ti-select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    padding-right: 32px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238B8478' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 14px 14px;
}

[data-theme="glass"] .ti-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23A6ACB8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}

/* Hide the legacy IE/Edge native arrow if the engine still renders it. */
.ti-select::-ms-expand {
    display: none;
}

/* Date input — leave the base padding alone (extra padding-right would shrink the content box and
   drag the calendar icon left of where it naturally sits, which is what we're trying to match). */
.ti-input[type="date"]::-webkit-calendar-picker-indicator {
    cursor: pointer;
    opacity: 0.7;
}

.ti-input[type="date"]::-webkit-calendar-picker-indicator:hover {
    opacity: 1;
}

.ti-field-label {
    display: block;
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--fg-secondary);
    margin-bottom: 6px;
    letter-spacing: -0.005em;
}

/* ============================================================
   Status pill
   ============================================================ */
.ti-status-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 22px;
    padding: 0 9px;
    border-radius: var(--r-pill);
    font-size: var(--fs-sm);
    font-weight: 500;
    letter-spacing: -0.005em;
    background: var(--muted-soft);
    color: var(--fg-secondary);
    white-space: nowrap;
}

.ti-status-pill .dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--muted);
    position: relative;
}

.ti-status-pill.success {
    background: var(--success-soft);
    color: var(--success);
}

.ti-status-pill.success .dot {
    background: var(--success);
}

.ti-status-pill.danger .dot::after,
.ti-status-pill.success .dot::after {
    content: "";
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    color: var(--success);
    border: 2px solid var(--success);
    opacity: 0;
    animation: statusPulse 1.6s var(--ease-out) infinite;
}

.ti-status-pill.info {
    background: var(--info-soft);
    color: var(--info);
}

.ti-status-pill.info .dot {
    background: var(--info);
}

.ti-status-pill.warn {
    background: var(--warn-soft);
    color: var(--warn);
}

.ti-status-pill.warn .dot {
    background: var(--warn);
}

.ti-status-pill.danger {
    background: var(--danger-soft);
    color: var(--danger);
}

.ti-status-pill.danger .dot {
    background: var(--danger);
}

.ti-status-pill.danger .dot::after {
    color: var(--danger);
    border: 2px solid var(--danger);
}

.ti-status-pill.muted {
    background: var(--muted-soft);
    color: var(--fg-tertiary);
}

.ti-status-pill.muted .dot {
    background: var(--fg-tertiary);
}

@keyframes statusPulse {
    0% {
        transform: scale(0.6);
        opacity: 0.5;
    }
    100% {
        transform: scale(1.8);
        opacity: 0;
    }
}


/* ============================================================
   Grade chips
   ============================================================ */
.ti-grade-chip {
    --c: var(--grade-N);
    --c-soft: var(--grade-N-soft);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    font-weight: 600;
    font-size: 13px;
    background: var(--c-soft);
    color: var(--c);
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast), border-color var(--dur-fast), box-shadow var(--dur-fast);
}

.ti-grade-chip[data-grade="S"] {
    --c: var(--grade-S);
    --c-soft: var(--grade-S-soft);
}

.ti-grade-chip[data-grade="R"] {
    --c: var(--grade-R);
    --c-soft: var(--grade-R-soft);
}

.ti-grade-chip[data-grade="U"] {
    --c: var(--grade-U);
    --c-soft: var(--grade-U-soft);
}

.ti-grade-chip[data-grade="N"] {
    --c: var(--grade-N);
    --c-soft: var(--grade-N-soft);
}

.ti-grade-chip.empty {
    background: transparent;
    color: var(--fg-tertiary);
    border: 1px dashed var(--border-strong);
}

/* An empty grade chip means the rating is still awaited — render an hourglass glyph (lucide) rather than a bare
   dash, so the "awaiting rating" state reads clearly wherever an empty chip is shown to a permitted viewer. */
.ti-grade-chip.empty::before {
    content: "";
    width: 12px;
    height: 12px;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 22h14'/%3E%3Cpath d='M5 2h14'/%3E%3Cpath d='M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22'/%3E%3Cpath d='M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 22h14'/%3E%3Cpath d='M5 2h14'/%3E%3Cpath d='M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22'/%3E%3Cpath d='M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2'/%3E%3C/svg%3E") center / contain no-repeat;
}

.ti-grade-chip.selectable:hover {
    transform: translateY(-1px);
    border-color: var(--c);
    box-shadow: 0 4px 10px color-mix(in oklab, var(--c) 24%, transparent);
}

.ti-grade-chip.selected {
    background: var(--c);
    color: var(--fg-on-accent);
    box-shadow: 0 4px 12px color-mix(in oklab, var(--c) 28%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.18);
    border-color: var(--c);
}

.ti-grade-chip.locked {
    cursor: default;
    opacity: 0.65;
}

.ti-grade-chip.locked.empty {
    opacity: 0.4;
}


/* ============================================================
   Avatar
   ============================================================ */
.ti-avatar {
    display: inline-grid;
    place-items: center;
    border-radius: 50%;
    background: var(--avatar-bg, var(--accent));
    color: #FFF;
    font-weight: 600;
    font-size: 12px;
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.ti-avatar.lg {
    width: 44px;
    height: 44px;
    font-size: 15px;
}

.ti-avatar.xl {
    width: 60px;
    height: 60px;
    font-size: 20px;
}

.ti-avatar.sm {
    width: 24px;
    height: 24px;
    font-size: 10.5px;
}

.ti-avatar.xs {
    width: 20px;
    height: 20px;
    font-size: 9px;
}

/* ============================================================
   Toast stack (replaces old notification bar)
   ============================================================ */
.ti-toast-stack {
    position: fixed;
    bottom: var(--s-5);
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    /* Above the modal layer (backdrop is z-index 1200) so a toast raised while a modal is open stays visible. */
    z-index: 1300;
    pointer-events: none;
}

.ti-toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: var(--s-3);
    padding: 12px 16px 12px 18px;
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-lg);
    min-width: 320px;
    max-width: 440px;
    position: relative;
    animation: toastIn 360ms var(--ease-out);
    overflow: hidden;
}

.ti-toast-bar {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background: var(--accent);
}

.ti-toast.success .ti-toast-bar {
    background: var(--success);
}

.ti-toast.warn .ti-toast-bar {
    background: var(--warn);
}

.ti-toast.danger .ti-toast-bar {
    background: var(--danger);
}

.ti-toast.info .ti-toast-bar {
    background: var(--info);
}

.ti-toast.leaving {
    animation: toastOut 300ms var(--ease-in-out) forwards;
}

.ti-toast-icon {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    margin-top: 1px;
    display: grid;
    place-items: center;
    color: var(--fg-secondary);
}

.ti-toast-icon svg {
    width: 18px;
    height: 18px;
}

.ti-toast.success .ti-toast-icon {
    color: var(--success);
}

.ti-toast.warn .ti-toast-icon {
    color: var(--warn);
}

.ti-toast.danger .ti-toast-icon {
    color: var(--danger);
}

.ti-toast.info .ti-toast-icon {
    color: var(--info);
}

.ti-toast-body {
    flex: 1;
    min-width: 0;
}

.ti-toast-title {
    font-weight: 600;
    font-size: var(--fs-base);
    color: var(--fg-primary);
}

.ti-toast-desc,
.ti-toast-msg {
    font-size: var(--fs-sm);
    color: var(--fg-secondary);
    margin-top: 2px;
}

.ti-toast-details {
    font-size: var(--fs-xs);
    color: var(--fg-tertiary);
    margin-top: 3px;
    line-height: 1.4;
    overflow-wrap: anywhere;
}

.ti-toast-close {
    flex: 0 0 auto;
    background: none;
    border: none;
    cursor: pointer;
    padding: 2px;
    color: var(--fg-tertiary);
    border-radius: 4px;
    line-height: 1;
    transition: color var(--dur-fast), background var(--dur-fast);
}

.ti-toast-close:hover {
    color: var(--fg-primary);
    background: var(--bg-tint);
}

@keyframes toastIn {
    from {
        opacity: 0;
        transform: translateY(12px) scale(0.96);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

@keyframes toastOut {
    from {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
    to {
        opacity: 0;
        transform: translateY(6px) scale(0.97);
    }
}

/* ============================================================
   Modal / dialog overlay — shared web-framework primitive.

   This is the canonical modal chrome for every ti-engine app. Use
   the following structure in any HTML fragment:

     <template x-if="modal.kind === 'foo'">
       <div class="ti-modal-backdrop" @click.self="closeModal()" @keydown.escape.window="closeModal()">
         <div class="ti-modal medium" role="dialog" aria-modal="true">
           <div class="ti-modal-head">
             <div class="ti-modal-head-content">
               <span class="ti-modal-eyebrow">…</span>
               <div class="ti-modal-title">…</div>
             </div>
             <button class="ti-modal-close" @click="closeModal()" aria-label="Close">
               <span class="ti-icon close md" aria-hidden="true"></span>
             </button>
           </div>
           <div class="ti-modal-body">…</div>
           <div class="ti-modal-foot">…</div>
         </div>
       </div>
     </template>

   Size variants: medium (640), large (880), full (~1100). Tone
   variants: danger (red head), warn (amber head). Footer alignment
   variants: between (space-between), start (flex-start).

   App-specific styles (e.g. .competence-cycle-lock-target) live in
   the app's CSS and target content inside .ti-modal-body. Don't
   override .ti-modal-* in app CSS — extend with a new wrapper class.
   ============================================================ */
.ti-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: 1200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--s-5);
    animation: modalBackdropIn var(--dur-base) var(--ease-out);
}

[data-theme="glass"] .ti-modal-backdrop {
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.ti-modal {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lg);
    width: 100%;
    max-width: 480px;
    max-height: calc(100vh - var(--s-7));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    animation: modalIn var(--dur-base) var(--ease-out);
}

.ti-modal.medium {
    max-width: 640px;
}

.ti-modal.large {
    max-width: 880px;
}

.ti-modal.full {
    max-width: min(1100px, 100% - var(--s-7));
}

.ti-modal-head-content {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    gap: var(--s-1);
}

.ti-modal-head {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding: var(--s-4) var(--s-5);
    border-bottom: 1px solid var(--border-soft);
    background: var(--bg-sunken);
}

.ti-modal-title {
    flex: 1;
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--fg-primary);
    line-height: 1.3;
}

.ti-modal-eyebrow {
    display: block;
    font-size: var(--fs-xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--fg-tertiary);
    padding: 0 var(--s-1);
}

.ti-modal-close {
    flex: 0 0 auto;
    background: none;
    border: none;
    cursor: pointer;
    padding: 4px;
    color: var(--fg-tertiary);
    border-radius: var(--r-xs);
    line-height: 1;
    display: grid;
    place-items: center;
    transition: color var(--dur-fast), background var(--dur-fast);
}

.ti-modal-close:hover {
    color: var(--fg-primary);
    background: var(--bg-tint);
}

.ti-modal-close svg {
    width: 16px;
    height: 16px;
}

.ti-modal-body {
    flex: 1 1 auto;
    overflow-y: auto;
    overscroll-behavior: none;
    padding: var(--s-5);
    color: var(--fg-primary);
    font-size: var(--fs-base);
    line-height: 1.5;
}

.ti-modal-body p {
    margin: 0 0 var(--s-3) 0;
}

.ti-modal-body p:last-child {
    margin-bottom: 0;
}

.ti-modal-foot {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--s-3);
    padding: var(--s-3) var(--s-5);
    border-top: 1px solid var(--border-soft);
    background: var(--bg-sunken);
}

.ti-modal-foot.between {
    justify-content: space-between;
}

.ti-modal-foot.start {
    justify-content: flex-start;
}

.ti-modal.danger .ti-modal-head {
    background: var(--danger-soft);
}

.ti-modal.danger .ti-modal-title {
    color: var(--danger);
}

.ti-modal.warn .ti-modal-head {
    background: var(--warn-soft);
}

.ti-modal.warn .ti-modal-title {
    color: var(--warn);
}

@keyframes modalBackdropIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

@keyframes modalIn {
    from {
        opacity: 0;
        transform: translateY(8px) scale(0.97);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

/* ============================================================
   KV grid (label / value pairs)
   ============================================================ */
.ti-kv-grid {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--s-2) var(--s-4);
    align-items: baseline;
}

.ti-kv-label {
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--fg-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    white-space: nowrap;
}

.ti-kv-value {
    font-size: var(--fs-sm);
    font-weight: 400;
    color: var(--fg-primary);
}

.ti-kv-value.mono {
    font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: var(--fs-xs);
}

/* Dimmed value — a hint, a placeholder, or a fact that is deliberately secondary. */
.ti-kv-value.muted {
    color: var(--fg-tertiary);
}

/* ============================================================
   Identity header + info sections — the read-only "facts"
   pattern behind the Profile and About screens. An application
   supplies the content as a descriptor; this supplies the
   layout, so every consumer's screens look the same.
   ============================================================ */
.ti-identity {
    display: flex;
    align-items: center;
    gap: var(--s-4);
    padding: var(--s-5);
}

/* Square brand/app mark, for an identity block that stands for an application rather than a person
   (the circular .ti-avatar is the person case). Mirrors the sidebar brand mark at a larger size. */
.ti-identity-mark {
    width: 60px;
    height: 60px;
    display: grid;
    place-items: center;
    border-radius: var(--r-lg);
    background: linear-gradient(135deg, var(--accent), color-mix(in oklab, var(--accent) 70%, #000));
    color: #FFF;
    font-weight: 700;
    font-size: 26px;
    letter-spacing: -0.02em;
    text-transform: uppercase;
    box-shadow: 0 4px 12px color-mix(in oklab, var(--accent) 32%, transparent), inset 0 1px 0 rgba(255, 255, 255, 0.25);
    flex: 0 0 auto;
}

.ti-identity-meta {
    flex: 1;
    min-width: 0;
}

.ti-identity-name {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s-2);
    font-size: var(--fs-2xl);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.1;
    color: var(--fg-primary);
}

.ti-identity-sub {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    font-size: var(--fs-sm);
    color: var(--fg-secondary);
    margin-top: var(--s-1);
}

.ti-identity-sub-sep {
    color: var(--fg-tertiary);
}

.ti-identity-caption {
    font-size: var(--fs-sm);
    color: var(--fg-tertiary);
    margin-top: 2px;
    overflow-wrap: anywhere;
}

/* Right-hand stack of status pills / tags. */
.ti-identity-aside {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--s-1);
    flex: 0 0 auto;
}

/* Two-up grid of section panels; a section may claim the full row with .wide. */
.ti-info-sections {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s-5);
    margin-top: var(--s-5);
    align-items: start;
}

.ti-info-section.wide {
    grid-column: 1 / -1;
}

@media (max-width: 900px) {
    .ti-info-sections {
        grid-template-columns: 1fr;
    }
}

/* Label/value pairs inside a section, stacked (label above value) rather than the side-by-side
   rhythm of .ti-kv-grid — a read-only mirror of the .ti-form-grid a matching edit screen uses. */
.ti-info-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s-4);
    padding: var(--s-5);
}

.ti-info-item {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.ti-info-item.wide {
    grid-column: 1 / -1;
}

/* An info value that is a destination rather than a fact. Only http(s)/mailto targets ever reach it — the
   normalizer in ti-framework.js drops anything else before it can become an href. */
.ti-info-link {
    color: var(--accent);
    text-decoration: none;
    overflow-wrap: anywhere;
}

.ti-info-link:hover {
    text-decoration: underline;
}

/* ============================================================
   Tag / pill label
   ============================================================ */
.ti-tag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 20px;
    padding: 0 8px;
    border-radius: var(--r-pill);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    background: var(--muted-soft);
    color: var(--fg-tertiary);
    white-space: nowrap;
}

.ti-tag.mono {
    font-family: "JetBrains Mono", monospace;
    letter-spacing: 0;
    text-transform: none;
}

/* ============================================================
   Empty state
   ============================================================ */
.ti-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--s-3);
    padding: var(--s-10) var(--s-6);
    text-align: center;
}

.ti-empty-state-icon {
    width: 48px;
    height: 48px;
    opacity: 0.3;
}

.ti-empty-state-title {
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--fg-primary);
}

.ti-empty-state-desc {
    font-size: var(--fs-base);
    color: var(--fg-tertiary);
    max-width: 40ch;
    line-height: 1.55;
}

/* ============================================================
   Page layout helpers — eyebrow / title / subtitle stacked
   vertically. Used as the single canonical page header pattern
   across every screen.
   ============================================================ */
.ti-page-head {
    display: flex;
    flex-direction: column;
    margin-bottom: var(--s-5);
    gap: var(--s-1);
}

.ti-page-eyebrow {
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--fg-tertiary);
    padding: 0 var(--s-1)
}

.ti-page-title {
    font-size: var(--fs-2xl);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.15;
    color: var(--fg-primary);
    margin: 0;
}

.ti-page-subtitle {
    color: var(--fg-tertiary);
    margin: 0;
    font-size: var(--fs-sm);
    line-height: 1.55;
    padding: var(--s-1);
}

/* ============================================================
   Form layout helpers — single canonical pattern for modal /
   master-detail / panel forms. Compose grid + row + section
   instead of cloning per-screen CSS.
   ============================================================ */
.ti-form {
    display: flex;
    flex-direction: column;
    gap: var(--s-5);
}

.ti-form.compact {
    gap: var(--s-4);
}

.ti-form-section {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
}

.ti-form-section-title {
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--fg-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.ti-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-3);
}

.ti-form-grid.cols-1 {
    grid-template-columns: 1fr;
}

.ti-form-grid.cols-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.ti-form-row {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}

.ti-form-row.wide {
    grid-column: 1 / -1;
}

.ti-form-readonly {
    padding: 6px 0;
    color: var(--fg-primary);
    font-size: var(--fs-base);
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ti-form-hint {
    font-size: var(--fs-xs);
    color: var(--fg-tertiary);
}

.ti-form-error {
    color: var(--danger);
    font-size: var(--fs-sm);
    background: var(--danger-soft);
    border: 1px solid var(--danger);
    padding: var(--s-2) var(--s-3);
    border-radius: var(--r-sm);
}

.ti-form-actions {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding-top: var(--s-3);
    border-top: 1px solid var(--border-soft);
}

.ti-form-state {
    flex: 1;
    font-size: var(--fs-sm);
}

.ti-form-state.saved {
    color: var(--success);
}

.ti-form-state.unsaved {
    color: var(--warn);
    font-weight: 500;
}

@media (max-width: 720px) {
    .ti-form-grid,
    .ti-form-grid.cols-3 {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   Data grid — CSS-grid replacement for <table>. Pass column
   widths via --ti-grid-cols (set on the wrapper or on a parent
   class). Head + rows share the same template so cells align.
   Use .ti-cell-center / .ti-cell-right on any direct grid child
   to override alignment.
   ============================================================ */
.ti-data-grid {
    width: 100%;
    /* Sensible single-column fallback. Override on a screen-specific class. */
    --ti-grid-cols: 1fr;
}

.ti-data-grid-head {
    display: grid;
    grid-template-columns: var(--ti-grid-cols);
    gap: var(--s-3);
    padding: var(--s-2) var(--s-5);
    font-size: var(--fs-xxs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-tertiary);
    border-bottom: 1px solid var(--border-soft);
    white-space: nowrap;
    align-items: center;
}

.ti-data-grid-rows {
    display: flex;
    flex-direction: column;
}

.ti-data-grid-row {
    display: grid;
    grid-template-columns: var(--ti-grid-cols);
    gap: var(--s-3);
    align-items: center;
    padding: var(--s-3) var(--s-5);
    transition: background var(--dur-fast);
    color: var(--fg-primary);
    font-size: var(--fs-sm);
}

.ti-data-grid-row:hover {
    background: var(--bg-tint);
}

/* Highlight the row representing the current user / actor. Used by the org tree to mark
   "this is you". */
.ti-data-grid-row.is-current {
    background: var(--accent-soft);
}

.ti-data-grid-row.is-current:hover {
    background: color-mix(in oklab, var(--accent-soft) 80%, var(--accent) 6%);
}

/* Highlight a user-picked row (e.g., selected cycle, selected employee). */
.ti-data-grid-row.is-selected {
    background: var(--accent-soft);
    border-left: 2px solid var(--accent);
    padding-left: calc(var(--s-5) - 2px);
}

/* Bordered variant — visible horizontal divider between rows. Use on tabular displays. */
.ti-data-grid.bordered .ti-data-grid-row {
    border-bottom: 1px solid var(--border-soft);
}

.ti-data-grid.bordered .ti-data-grid-row:last-child {
    border-bottom: 0;
}

/* Compact variant — tighter row padding for dense data. */
.ti-data-grid.compact .ti-data-grid-row,
.ti-data-grid.compact .ti-data-grid-head {
    padding: var(--s-2) var(--s-4);
}

/* Per-cell alignment utilities. Apply directly to any grid-child element
   (span / div / button) to override the default left alignment. */
.ti-cell-center {
    justify-self: center;
    text-align: center;
}

.ti-cell-right {
    justify-self: end;
    text-align: right;
}

/* ============================================================
   Login ti-page
   ============================================================ */
#ti-login {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    width: 100%;
    background: var(--bg-app);
}

.ti-login-container {
    width: 100%;
    max-width: 400px;
    padding: var(--s-5);
}

.ti-login-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--s-3);
    margin-bottom: var(--s-7);
}

.ti-login-brand-mark {
    width: 48px;
    height: 48px;
    border-radius: 14px;
    background: linear-gradient(135deg, var(--accent), color-mix(in oklab, var(--accent) 70%, #000));
    display: grid;
    place-items: center;
    color: #fff;
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.02em;
    box-shadow: 0 8px 24px color-mix(in oklab, var(--accent) 28%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, 0.25);
}

.ti-login-brand-text {
    text-align: center;
}

.ti-login-brand-title {
    font-size: var(--fs-xl);
    font-weight: 700;
    letter-spacing: -0.025em;
    color: var(--fg-primary);
}

.ti-login-brand-sub {
    font-size: var(--fs-base);
    color: var(--fg-tertiary);
    margin-top: 4px;
}

.ti-login-card {
    background: var(--bg-surface);
    border: 1px solid var(--border);
    border-radius: var(--r-xl);
    padding: var(--s-6);
    box-shadow: var(--shadow-lg);
}

/* The language switch (CA-410): a footer row under the sign-in methods, drawn only when two or more languages are
   offered. Plain links, so it needs no script; the current language is marked by the server with `aria-current`. */
.ti-login-card-foot {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    margin-top: var(--s-5);
    padding-top: var(--s-4);
    border-top: 1px solid var(--border-soft);
}

.ti-login-languages {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    overflow: hidden;
}

.ti-login-language {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    height: 28px;
    padding: 0 var(--s-2);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--fg-secondary);
    text-decoration: none;
}

.ti-login-language + .ti-login-language {
    border-left: 1px solid var(--border);
}

.ti-login-language:hover {
    background: var(--bg-tint);
    color: var(--fg-primary);
}

.ti-login-language[aria-current="true"] {
    background: var(--accent-soft);
    color: var(--accent);
}

/* Inside the switch's edge, which clips anything drawn outside it. */
.ti-login-language:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

.ti-login-error {
    display: none;
    color: var(--danger);
    font-size: var(--fs-sm);
    margin-bottom: var(--s-4);
    padding: var(--s-3);
    background: var(--danger-soft);
    border-radius: var(--r-md);
}

.ti-login-error.visible {
    display: block;
}

.ti-login-form {
    display: flex;
    flex-direction: column;
    gap: var(--s-4);
}

.ti-login-submit {
    margin-top: var(--s-1);
}

.ti-login-divider {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    margin: var(--s-5) 0;
}

.ti-login-divider-line {
    flex: 1;
    height: 1px;
    background: var(--border);
}

.ti-login-divider-label {
    font-size: var(--fs-xs);
    color: var(--fg-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
}

.ti-login-social {
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}

.ti-btn.full {
    width: 100%;
}

/* ============================================================
   Utility
   ============================================================ */
* {
    box-sizing: border-box;
}

/* Flexible spacer: pushes following siblings to the far end of a flex row/column. */
.ti-spacer {
    flex: 1 1 auto;
}

::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--border, rgba(0, 0, 0, 0.15));
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--border-strong, rgba(0, 0, 0, 0.28));
    background-clip: padding-box;
    border: 2px solid transparent;
}

/* ------------------------------------------------------------------ *
 *  ti-charts — themeable SVG chart primitives (Phase 0: gauge/bars/stat)
 *  Colors route through semantic + grade tokens that flip per theme in
 *  ti-theme-daylight.css / ti-theme-black-glass.css. No per-chart overrides.
 *
 *  Chart ink — text, stroke widths, marker dots — is sized in CSS pixels.
 *  Inside an SVG with a viewBox a CSS pixel is one user unit, which scales
 *  with the card, so each of those sizes is multiplied by --ti-chart-u: the
 *  size of one screen pixel in viewBox units, measured per chart by
 *  ti-charts.js and kept current by a ResizeObserver. Until it is measured
 *  (a hidden card, no layout) the var() fallback gives back the unit size the
 *  rule had before: calc(var(--fs-xs) * calc(4 / 11)) is the old 4. Without
 *  it a 720px chart drew 26px labels beside its 12px legend, and a 280px one
 *  drew them at 5px. The gauge keeps unit sizes: its text is part of the dial.
 * ------------------------------------------------------------------ */
.ti-chart {
    --c-axis: var(--border-strong);
    --c-grid: var(--grid-line);
    --c-ink: var(--fg-secondary);
    --c-ink-strong: var(--fg-primary);
    --c-series-1: var(--accent);
    --c-series-2: var(--info);
    --c-series-3: var(--success);
    --c-grade-s: var(--grade-S);
    --c-grade-r: var(--grade-R);
    --c-grade-u: var(--grade-U);
    --c-grade-n: var(--grade-N);
    --c-seq-1: var(--chart-seq-1);
    --c-seq-2: var(--chart-seq-2);
    --c-seq-3: var(--chart-seq-3);
    --c-seq-4: var(--chart-seq-4);
    --c-seq-5: var(--chart-seq-5);
    display: block;
    margin: 0;
    position: relative;
}

.ti-chart svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
    /* Charts scale to 100% of their card; cap the height (and per-type width below) + centre so a chart on a wide card
       does not balloon to many hundreds of px tall. preserveAspectRatio="xMidYMid meet" keeps the drawing centred. */
    max-height: 460px;
    margin-inline: auto;
}

/* Per-type size caps (the figure carries data-ti-chart-type, set by renderChart). Square KPIs stay small and centred;
   content charts use width but never overrun the height cap. */
.ti-chart[data-ti-chart-type="gauge"] svg {
    max-width: 240px;
}

.ti-chart[data-ti-chart-type="scatter"] svg {
    max-width: 380px;
}

.ti-chart[data-ti-chart-type="heatmap"] svg {
    max-width: 480px;
}

.ti-chart[data-ti-chart-type="box"] svg {
    max-width: 680px;
}

/* Horizontal bars grow with their row count, so they opt out of the global max-height: with the cap, a tall org-wide
   chart was uniformly scaled down and ended up finer than the same chart on a smaller subtree. Without it the bar
   thickness and label size stay identical across screens; the chart simply gets taller when there are more rows. */
.ti-chart[data-ti-chart-type="bars"] svg {
    max-width: 640px;
    max-height: none;
}

/* Bars lay out in pixels, with no viewBox (ti-charts.js BAR_RHYTHM): one user unit is one CSS pixel, so the scale
   chart ink is multiplied by is 1 by construction rather than measured. */
.ti-chart svg.ti-chart-flow {
    --ti-chart-u: 1;
}

.ti-chart[data-ti-chart-type="radar"] svg {
    max-width: 360px;
}

.ti-chart[data-ti-chart-type="line"] svg {
    max-width: 640px;
}

/* Visually-hidden a11y mirror table (screen-reader only). */
.ti-chart-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Provisional ("as of now / % reporting") visual language — class form;
   renderers may instead set stroke-dasharray as a presentation attribute. */
.ti-chart-provisional {
    stroke-dasharray: calc(4px * var(--ti-chart-u, 1)) calc(3px * var(--ti-chart-u, 1));
    opacity: 0.55;
}

/* --- gauge --- */
.ti-chart-gauge-track {
    stroke: var(--c-grid);
    stroke-width: 8;
    stroke-linecap: round;
}

.ti-chart-gauge-arc {
    stroke: var(--c-series-1);
    stroke-width: 8;
    stroke-linecap: round;
}

.ti-chart-gauge-value {
    fill: var(--c-ink-strong);
    font-size: 18px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.ti-chart-gauge-label {
    fill: var(--c-ink);
    font-size: 7px;
}

.ti-chart-gauge-sublabel {
    fill: var(--c-ink);
    font-size: 5px;
}

/* --- bars --- */
.ti-chart-bar-seg {
    fill: var(--c-series-1);
}

.ti-chart-bar-seg.tone-grade-s {
    fill: var(--c-grade-s);
}

.ti-chart-bar-seg.tone-grade-r {
    fill: var(--c-grade-r);
}

.ti-chart-bar-seg.tone-grade-u {
    fill: var(--c-grade-u);
}

.ti-chart-bar-seg.tone-grade-n {
    fill: var(--c-grade-n);
}

.ti-chart-bar-seg.tone-ink {
    fill: var(--c-grid);
}

.ti-chart-bar-seg.tone-info {
    fill: var(--c-series-2);
}

/* --- stat tile --- */
.ti-chart-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ti-chart-stat-value {
    color: var(--c-ink-strong);
    font-size: 1.6rem;
    font-weight: 600;
    line-height: 1.1;
}

.ti-chart-stat-label {
    color: var(--c-ink-strong);
    font-size: 0.9rem;
}

.ti-chart-stat-sub {
    color: var(--c-ink);
    font-size: 0.8rem;
}

.ti-chart-stat-bar {
    height: 6px;
    border-radius: 999px;
    background: var(--c-grid);
    overflow: hidden;
    margin-top: 4px;
}

.ti-chart-stat-fill {
    height: 100%;
    width: var(--pct, 0%);
    background: var(--c-series-1);
    border-radius: inherit;
}

/* tabular-nums utility used by chart text (no such class existed before). */
.tabular-nums {
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ *
 *  ti-charts — Phase 1A primitives (scatter, heatmap, box) + bar modes.
 *  Same token discipline: colors route through --c-* (set on .ti-chart).
 * ------------------------------------------------------------------ */

/* Interactive marks (drill) — CSP-safe: tabindex/role set in JS, no inline handlers. */
.ti-chart [role="button"] {
    cursor: pointer;
}

.ti-chart [role="button"]:focus-visible {
    outline: 1px solid var(--c-series-1);
    outline-offset: 1px;
}

/* --- scatter (R3 alignment quadrant) --- */
.ti-chart-scatter-diag {
    stroke: var(--c-grid);
    stroke-width: calc(1.5px * var(--ti-chart-u, calc(0.5 / 1.5)));
    stroke-dasharray: calc(4px * var(--ti-chart-u, 0.5)) calc(4px * var(--ti-chart-u, 0.5));
}

.ti-chart-scatter-mid {
    stroke: var(--c-grid);
    stroke-width: calc(1px * var(--ti-chart-u, 0.4));
}

.ti-chart-scatter-pt {
    fill: var(--c-series-1);
    stroke: var(--c-ink-strong);
    stroke-width: calc(1px * var(--ti-chart-u, 0.3));
}

.ti-chart-scatter-pt.tone-grade-s {
    fill: var(--c-grade-s);
}

.ti-chart-scatter-pt.tone-grade-r {
    fill: var(--c-grade-r);
}

.ti-chart-scatter-pt.tone-grade-u {
    fill: var(--c-grade-u);
}

.ti-chart-scatter-pt.tone-grade-n {
    fill: var(--c-grade-n);
}

.ti-chart-scatter-pt.tone-info {
    fill: var(--c-series-2);
}

.ti-chart-scatter-quad {
    fill: var(--c-series-1);
    opacity: 0.05;
}

.ti-chart-axis-label {
    fill: var(--c-ink);
    font-size: calc(var(--fs-xs) * var(--ti-chart-u, calc(4 / 11)));
}

/* --- heatmap (R4) — sequential ramp + diverging grade scale --- */
.ti-chart-heat-cell {
    stroke: var(--bg-elevated, #fff);
    stroke-width: calc(2px * var(--ti-chart-u, 0.25));
}

.ti-chart-heat-cell.cell-q1 {
    fill: var(--c-seq-1);
}

.ti-chart-heat-cell.cell-q2 {
    fill: var(--c-seq-2);
}

.ti-chart-heat-cell.cell-q3 {
    fill: var(--c-seq-3);
}

.ti-chart-heat-cell.cell-q4 {
    fill: var(--c-seq-4);
}

.ti-chart-heat-cell.cell-q5 {
    fill: var(--c-seq-5);
}

.ti-chart-heat-cell.cell-pos {
    fill: var(--c-grade-s);
}

/* diverging: positive gap → S side */
.ti-chart-heat-cell.cell-neg {
    fill: var(--c-grade-n);
}

/* diverging: negative gap → N side */
.ti-chart-heat-cell.cell-zero {
    fill: var(--c-grid);
}

.ti-chart-heat-cell.suppressed {
    fill: var(--c-grid);
    opacity: 0.4;
}

.ti-chart-heat-label {
    fill: var(--c-ink);
    font-size: calc(var(--fs-xs) * var(--ti-chart-u, calc(4 / 11)));
}

/* --- box (R5 level correlation) --- */
.ti-chart-box-box {
    fill: var(--c-series-1);
    opacity: 0.22;
    stroke: var(--c-series-1);
    stroke-width: calc(1.5px * var(--ti-chart-u, calc(0.6 / 1.5)));
}

.ti-chart-box-median {
    stroke: var(--c-ink-strong);
    stroke-width: calc(2px * var(--ti-chart-u, 0.5));
}

.ti-chart-box-whisker {
    stroke: var(--c-axis);
    stroke-width: calc(1px * var(--ti-chart-u, 0.5));
}

.ti-chart-box-cap {
    stroke: var(--c-axis);
    stroke-width: calc(1px * var(--ti-chart-u, 0.5));
}

.ti-chart-box-mean {
    fill: var(--c-ink-strong);
    r: calc(3px * var(--ti-chart-u, 0.3));
}

.ti-chart-box-expected {
    stroke: var(--c-grade-r);
    stroke-width: calc(2px * var(--ti-chart-u, 0.4));
    stroke-dasharray: calc(4px * var(--ti-chart-u, 0.5)) calc(4px * var(--ti-chart-u, 0.5));
}

.ti-chart-box-ref {
    stroke: var(--c-grade-u);
    stroke-width: calc(1px * var(--ti-chart-u, 0.5));
    stroke-dasharray: calc(6px * var(--ti-chart-u, 0.5)) calc(4px * var(--ti-chart-u, 0.5));
}

.ti-chart-box-ref-label {
    fill: var(--c-grade-u);
    font-size: calc(var(--fs-xs) * var(--ti-chart-u, calc(4 / 11)));
}

.ti-chart-box-label {
    fill: var(--c-ink);
    font-size: calc(var(--fs-xs) * var(--ti-chart-u, calc(4 / 11)));
}

/* --- bars (grouped + diverging modes) --- */
.ti-chart-bar-axis {
    stroke: var(--c-axis);
    stroke-width: calc(1px * var(--ti-chart-u, 0.4));
}

.ti-chart-bar-label {
    fill: var(--c-ink);
    font-size: calc(var(--fs-sm) * var(--ti-chart-u, calc(4 / 12)));
}

/* Grouped-bar value caption. A caption carrying a font-size attribute — the deprecated valueFontSize option, in viewBox
   units — is left to it, because any font-size rule matching it would override the attribute. */
.ti-chart-bar-value {
    fill: var(--c-ink);
}

.ti-chart-bar-value:not([font-size]) {
    font-size: calc(var(--fs-xs) * var(--ti-chart-u, calc(4 / 11)));
}

/* Chart legend — a visible swatch+label key appended below a chart (e.g. the coverage stacked bars). Inherits the
   --c-grade-* / --c-ink tokens from the parent .ti-chart, so swatches match the segment fills and re-theme with them. */
.ti-chart-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--s-2) var(--s-4);
    margin-top: var(--s-3);
    font-size: var(--fs-sm);
    color: var(--fg-secondary);
}

.ti-chart-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.ti-chart-legend-swatch {
    width: 12px;
    height: 12px;
    border-radius: 3px;
    background: var(--c-ink);
    flex: 0 0 auto;
}

.ti-chart-legend-swatch.tone-grade-s {
    background: var(--c-grade-s);
}

.ti-chart-legend-swatch.tone-grade-r {
    background: var(--c-grade-r);
}

.ti-chart-legend-swatch.tone-grade-u {
    background: var(--c-grade-u);
}

.ti-chart-legend-swatch.tone-grade-n {
    background: var(--c-grade-n);
}

.ti-chart-legend-swatch.tone-ink {
    background: var(--c-ink);
}

.ti-chart-legend-swatch.tone-info {
    background: var(--c-series-2);
}

.ti-chart-legend-swatch.is-dashed {
    background: transparent;
    border: 1px dashed var(--c-ink);
}

/* --- radar (individual subcategory profile) --- */
.ti-chart-radar-ring {
    stroke: var(--c-grid);
    stroke-width: calc(1px * var(--ti-chart-u, 0.4));
}

.ti-chart-radar-spoke {
    stroke: var(--c-grid);
    stroke-width: calc(1px * var(--ti-chart-u, 0.3));
}

.ti-chart-radar-axis-label {
    fill: var(--c-ink);
    font-size: calc(var(--fs-xs) * var(--ti-chart-u, calc(3.6 / 11)));
}

.ti-chart-radar-poly {
    fill: var(--c-series-1);
    fill-opacity: 0.12;
    stroke: var(--c-series-1);
    stroke-width: calc(2px * var(--ti-chart-u, 0.4));
}

/* A dashed series (the "expected" curve, or a provisional one) gets its dash from the renderer as a presentation
   attribute in viewBox units; this rule restates it in pixels, and outranks the attribute as any rule does. */
.ti-chart-radar-poly[stroke-dasharray] {
    stroke-dasharray: calc(8px * var(--ti-chart-u, 0.375)) calc(6px * var(--ti-chart-u, calc(2 / 6)));
}

.ti-chart-radar-poly.tone-grade-s {
    fill: var(--c-grade-s);
    stroke: var(--c-grade-s);
}

.ti-chart-radar-poly.tone-grade-r {
    fill: var(--c-grade-r);
    stroke: var(--c-grade-r);
}

.ti-chart-radar-poly.tone-grade-u {
    fill: var(--c-grade-u);
    stroke: var(--c-grade-u);
}

.ti-chart-radar-poly.tone-grade-n {
    fill: var(--c-grade-n);
    stroke: var(--c-grade-n);
}

.ti-chart-radar-poly.tone-info {
    fill: var(--c-series-2);
    stroke: var(--c-series-2);
}

.ti-chart-radar-dot {
    fill: var(--c-series-1);
    r: calc(3px * var(--ti-chart-u, 0.3));
}

.ti-chart-radar-dot.tone-grade-s {
    fill: var(--c-grade-s);
}

.ti-chart-radar-dot.tone-grade-r {
    fill: var(--c-grade-r);
}

.ti-chart-radar-dot.tone-grade-u {
    fill: var(--c-grade-u);
}

.ti-chart-radar-dot.tone-grade-n {
    fill: var(--c-grade-n);
}

.ti-chart-radar-dot.tone-info {
    fill: var(--c-series-2);
}

/* --- line / trend (cross-cycle, CA-X1) --- */
.ti-chart-line-axis {
    stroke: var(--c-grid);
    stroke-width: calc(1px * var(--ti-chart-u, 0.3));
}

.ti-chart-line-xlabel {
    fill: var(--c-ink);
    font-size: calc(var(--fs-xs) * var(--ti-chart-u, calc(3.2 / 11)));
}

.ti-chart-line-series {
    stroke: var(--c-series-1);
    stroke-width: calc(2px * var(--ti-chart-u, 0.5));
    fill: none;
    stroke-linejoin: round;
    stroke-linecap: round;
}

/* Dashed series and the provisional tail: see .ti-chart-radar-poly[stroke-dasharray]. The round caps add a pixel to
   each end of a dash, so the gap is drawn wider than it reads. */
.ti-chart-line-series[stroke-dasharray] {
    stroke-dasharray: calc(8px * var(--ti-chart-u, 0.375)) calc(6px * var(--ti-chart-u, calc(2 / 6)));
}

.ti-chart-line-series.tone-grade-s {
    stroke: var(--c-grade-s);
}

.ti-chart-line-series.tone-grade-r {
    stroke: var(--c-grade-r);
}

.ti-chart-line-series.tone-grade-u {
    stroke: var(--c-grade-u);
}

.ti-chart-line-series.tone-grade-n {
    stroke: var(--c-grade-n);
}

.ti-chart-line-series.tone-info {
    stroke: var(--c-series-2);
}

.ti-chart-line-band {
    fill: var(--c-series-1);
    fill-opacity: 0.12;
    stroke: none;
}

.ti-chart-line-band.tone-grade-s {
    fill: var(--c-grade-s);
}

.ti-chart-line-band.tone-grade-r {
    fill: var(--c-grade-r);
}

.ti-chart-line-band.tone-grade-u {
    fill: var(--c-grade-u);
}

.ti-chart-line-band.tone-grade-n {
    fill: var(--c-grade-n);
}

.ti-chart-line-band.tone-info {
    fill: var(--c-series-2);
}

.ti-chart-line-dot {
    fill: var(--c-series-1);
    r: calc(4px * var(--ti-chart-u, 0.275));
}

/* A sparkline's dots stay small: it is a glyph beside text, not a chart to read values off. */
.ti-chart-sparkline .ti-chart-line-dot {
    r: calc(2px * var(--ti-chart-u, 0.4));
}

.ti-chart-line-dot.tone-grade-s {
    fill: var(--c-grade-s);
}

.ti-chart-line-dot.tone-grade-r {
    fill: var(--c-grade-r);
}

.ti-chart-line-dot.tone-grade-u {
    fill: var(--c-grade-u);
}

.ti-chart-line-dot.tone-grade-n {
    fill: var(--c-grade-n);
}

.ti-chart-line-dot.tone-info {
    fill: var(--c-series-2);
}

.ti-chart-line-dot.provisional {
    fill: var(--bg-app);
    stroke: var(--c-series-1);
    stroke-width: calc(1.5px * var(--ti-chart-u, 0.4));
}

.ti-chart-line-dot.tone-grade-s.provisional {
    stroke: var(--c-grade-s);
}

.ti-chart-line-dot.tone-grade-r.provisional {
    stroke: var(--c-grade-r);
}

.ti-chart-line-dot.tone-grade-u.provisional {
    stroke: var(--c-grade-u);
}

.ti-chart-line-dot.tone-grade-n.provisional {
    stroke: var(--c-grade-n);
}

.ti-chart-line-dot.tone-info.provisional {
    stroke: var(--c-series-2);
}

/* ============================================================
   Shared components (1.51.0, CA-479)
   Tones, stacks, meter, stat, card rows, steps, legend, dot,
   tag variants, segmented control, filter chip, danger buttons,
   drawer, outlined status pill, banner, kbd, sticky action bar,
   compact empty state, sidebar counter.
   Theme-agnostic: they read framework tokens only. They come
   last in this file, so they extend the rules above for
   .ti-btn, .ti-tag, .ti-status-pill and .ti-empty-state.
   ============================================================ */

:root {
    /* Font roles the components read. An application sets its own
       families over these. */
    --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas, monospace;
    --font-display: var(--font-sans);
    --font-brand: var(--font-display);
}

/* ---------- Tones ----------
   One pair of variables (--tone, --tone-soft) drives meters, legend
   swatches, dots and icon tiles. Put a tone class on the component. */
.tone-accent  { --tone: var(--accent);  --tone-soft: var(--accent-soft); }
.tone-success { --tone: var(--success); --tone-soft: var(--success-soft); }
.tone-warn    { --tone: var(--warn);    --tone-soft: var(--warn-soft); }
.tone-danger  { --tone: var(--danger);  --tone-soft: var(--danger-soft); }
.tone-info    { --tone: var(--info);    --tone-soft: var(--info-soft); }
.tone-muted   { --tone: var(--muted);   --tone-soft: var(--muted-soft); }
.tone-grade-s { --tone: var(--grade-S); --tone-soft: var(--grade-S-soft); }
.tone-grade-r { --tone: var(--grade-R); --tone-soft: var(--grade-R-soft); }
.tone-grade-u { --tone: var(--grade-U); --tone-soft: var(--grade-U-soft); }
.tone-grade-n { --tone: var(--grade-N); --tone-soft: var(--grade-N-soft); }

/* ---------- Layout stacks ----------
   A flex column with one of five gaps. */
.ti-stack-0, .ti-stack-1, .ti-stack-2, .ti-stack-3, .ti-stack-4 {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.ti-stack-0 { gap: 2px; }
.ti-stack-1 { gap: var(--s-1); }
.ti-stack-2 { gap: var(--s-2); }
.ti-stack-3 { gap: var(--s-3); }
.ti-stack-4 { gap: var(--s-4); }
.ti-row { display: flex; align-items: center; gap: var(--s-2); min-width: 0; }
.ti-row.wrap { flex-wrap: wrap; }
.ti-row.top { align-items: flex-start; }
.ti-row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); min-width: 0; }

/* ---------- Meter (progress bar) ----------
   <div class="ti-meter tone-accent"><span class="ti-meter-fill"></span></div>
   Width: set --value (e.g. 40%) or style.width on the fill. */
.ti-meter {
    --ti-meter-h: 4px;
    position: relative;
    display: block;
    height: var(--ti-meter-h);
    border-radius: var(--r-pill);
    background: var(--bg-sunken);
    overflow: hidden;
}
.ti-meter.sm { --ti-meter-h: 3px; }
.ti-meter.lg { --ti-meter-h: 6px; }
.ti-meter-fill {
    display: block;
    height: 100%;
    width: var(--value, 0%);
    border-radius: inherit;
    background: var(--tone, var(--accent));
    transition: width var(--dur-slow) var(--ease-out), background-color var(--dur-base);
}
/* Segmented: shares of one whole (weights, coverage). .on marks the
   highlighted share; .ti-share-N sets its relative size. */
.ti-meter.segmented {
    display: flex;
    gap: 3px;
    border-radius: 0;
    background: transparent;
    overflow: visible;
}
.ti-meter.segmented > .ti-meter-fill {
    width: auto;
    flex: var(--share, 1) 1 0;
    border-radius: 0;
    background: color-mix(in oklab, var(--tone, var(--accent)) 22%, transparent);
}
.ti-meter.segmented > .ti-meter-fill.on { background: var(--tone, var(--accent)); }
.ti-meter-scale {
    display: flex;
    gap: 3px;
    margin-top: 6px;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    color: var(--fg-secondary);
    white-space: nowrap;
}
.ti-meter-scale > * { flex: var(--share, 1) 1 0; min-width: 0; }
.ti-meter-scale > .on { color: var(--tone, var(--accent)); font-weight: 600; }
/* Stacked: each label over its value, for a scale whose labels outgrow their share on one line. A long word with
   "20%" is wider than a fifth of a 300px meter, so the one-line form overlapped its neighbour (CA-334). */
.ti-meter-scale.stacked > * { display: flex; flex-direction: column; gap: 1px; white-space: normal; }
.ti-meter-scale-label { font-family: var(--font-sans); overflow-wrap: anywhere; }
.ti-meter-scale-value { font-family: var(--font-mono); }
.ti-share-1 { --share: 1; }  .ti-share-2 { --share: 2; }  .ti-share-3 { --share: 3; }
.ti-share-4 { --share: 4; }  .ti-share-5 { --share: 5; }  .ti-share-6 { --share: 6; }
.ti-share-7 { --share: 7; }  .ti-share-8 { --share: 8; }  .ti-share-9 { --share: 9; }
.ti-share-10 { --share: 10; }

/* ---------- Stat ----------
   Label / figure / sub-line. */
.ti-stat { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ti-stat-label {
    font-size: var(--fs-xxs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--fg-tertiary);
}
.ti-stat-value {
    font-family: var(--font-display);
    font-size: 21px;
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: var(--fg-primary);
    font-variant-numeric: tabular-nums;
}
.ti-stat-value small, .ti-stat-value.empty { font-size: inherit; color: var(--fg-tertiary); }
.ti-stat-sub { font-size: var(--fs-sm); line-height: 1.45; color: var(--fg-secondary); }
.ti-stat-sub strong { font-family: var(--font-mono); font-weight: 600; color: var(--accent); }
.ti-stat.lg .ti-stat-value { font-size: var(--fs-2xl); }

/* ---------- Card rows and icon tile ----------
   Several facts, such as a deadline and a score, as rows of one card. */
.ti-card-rows { display: flex; flex-direction: column; }
.ti-card-row { display: flex; align-items: flex-start; gap: 14px; padding: 18px 20px; }
.ti-card-rows > .ti-card-row + .ti-card-row { border-top: 1px solid var(--border-soft); }
.ti-card-icon {
    width: 40px;
    height: 40px;
    flex: none;
    display: grid;
    place-items: center;
    border-radius: var(--r-sm);
    background: var(--tone-soft, var(--bg-sunken));
    color: var(--tone, var(--fg-secondary));
}

/* ---------- Steps (status track) ----------
   <div class="ti-steps"><span class="ti-step done">Open</span>
   <span class="ti-step-line done"></span><span class="ti-step current">In Review</span>… */
.ti-steps { display: flex; align-items: center; gap: 10px; min-width: 0; }
.ti-step {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--fg-tertiary);
    white-space: nowrap;
}
.ti-step::before {
    content: "";
    width: 14px;
    height: 14px;
    flex: none;
    box-sizing: border-box;
    border-radius: 50%;
    border: 1.5px solid currentColor;
    transition: border var(--dur-base), background-color var(--dur-base);
}
.ti-step.done { color: var(--fg-secondary); }
.ti-step.done::before { background: var(--accent); border-color: var(--accent); }
.ti-step.current { color: var(--fg-primary); font-weight: 600; }
.ti-step.current::before { border: 4px solid var(--accent); background: var(--bg-surface); }
.ti-step-line { flex: 1 1 auto; min-width: 16px; height: 1px; background: var(--border); }
.ti-step-line.done { background: var(--accent); }

/* ---------- Legend ----------
   One swatch and label per series, for a chart, a calendar or a scale. */
.ti-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-2) var(--s-4);
    font-size: var(--fs-sm);
    color: var(--fg-secondary);
}
.ti-legend.stacked { flex-direction: column; align-items: flex-start; gap: var(--s-2); }
.ti-legend-item { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.ti-legend-swatch {
    width: 10px;
    height: 10px;
    flex: none;
    box-sizing: border-box;
    border-radius: 2px;
    background: var(--tone, var(--fg-tertiary));
}
.ti-legend-swatch.round { border-radius: 50%; }
.ti-legend-swatch.dashed { background: transparent; border: 1px dashed var(--tone, var(--fg-tertiary)); }

/* ---------- Dot ---------- */
.ti-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    flex: none;
    border-radius: 50%;
    background: var(--tone, var(--fg-tertiary));
}
.ti-dot.square { border-radius: 1px; }
.ti-dot.hollow { background: transparent; box-shadow: inset 0 0 0 1.5px var(--fg-tertiary); }
/* Keeps its place in a row that has nothing to mark, so the rows beside it stay aligned. */
.ti-dot.blank { visibility: hidden; }

/* ---------- Tag variants ---------- */
.ti-tag.accent  { background: var(--accent-soft);  color: var(--accent); }
.ti-tag.success { background: var(--success-soft); color: var(--success); }
.ti-tag.info    { background: var(--info-soft);    color: var(--info); }
.ti-tag.warn    { background: var(--warn-soft);    color: var(--warn); }
.ti-tag.danger  { background: var(--danger-soft);  color: var(--danger); }
.ti-tag.outline { background: transparent; color: var(--fg-secondary); box-shadow: inset 0 0 0 1px var(--border-strong); }

/* ---------- Segmented control ----------
   One choice among a few, each with an optional count: a filter over one list. The chosen segment is filled in the
   accent. Each segment is a button carrying aria-pressed, which draws the choice and announces it; the group carries
   role="group" and an accessible name. Borders collapse, so the chosen segment's accent edge shows on every side.
   <div class="ti-segmented" role="group" aria-label="Status">
     <button type="button" class="ti-segmented-item" aria-pressed="true">All <span class="ti-segmented-count">7</span></button>
   </div> */
.ti-segmented { display: inline-flex; flex: none; }
.ti-segmented-item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 32px;
    padding: 0 12px;
    margin-left: -1px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--fg-secondary);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
}
/* Of type, not child: an Alpine x-for's <template> is the group's first child, so :first-child never matched a button. */
.ti-segmented-item:first-of-type { margin-left: 0; border-radius: var(--ti-button-radius) 0 0 var(--ti-button-radius); }
.ti-segmented-item:last-of-type { border-radius: 0 var(--ti-button-radius) var(--ti-button-radius) 0; }
.ti-segmented-item:hover { background: var(--bg-tint); color: var(--fg-primary); }
.ti-segmented-item[aria-pressed="true"] {
    z-index: 1;
    border-color: var(--accent);
    background: var(--accent);
    color: var(--fg-on-accent);
    font-weight: 600;
}
.ti-segmented-item:focus-visible { z-index: 2; outline: none; box-shadow: var(--shadow-focus); }
.ti-segmented-count { font-family: var(--font-mono); font-size: var(--fs-xs); opacity: 0.8; }

/* ---------- Filter chip ----------
   A toggle that narrows a list to one value, such as a cycle. Chosen: an accent hairline on the accent's tint. A button
   carrying aria-pressed; .mono for an ID. */
.ti-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 32px;
    padding: 0 11px;
    border: 1px solid var(--border);
    border-radius: var(--ti-button-radius);
    background: transparent;
    color: var(--fg-secondary);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
}
.ti-chip.mono { font-family: var(--font-mono); }
.ti-chip:hover { border-color: var(--border-strong); color: var(--fg-primary); }
.ti-chip[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.ti-chip:focus-visible { outline: none; box-shadow: var(--shadow-focus); }

/* ---------- Danger buttons ----------
   A destructive action beside a row's main one, as text: no fill and no border, its tint on hover. The framework's
   .danger is outlined and, written after .ghost, wins over it at equal specificity, so the pair needs its own rule.
   And the confirmation that carries one out, filled, as the last step of its dialog. */
.ti-btn.ghost.danger { border-color: transparent; color: var(--danger); }
.ti-btn.ghost.danger:hover { border-color: transparent; background: var(--danger-soft); color: var(--danger); }
.ti-btn.danger.solid { border-color: var(--danger); background: var(--danger); color: var(--fg-on-accent); }
.ti-btn.danger.solid:hover {
    border-color: color-mix(in oklab, var(--danger) 86%, var(--fg-primary));
    background: color-mix(in oklab, var(--danger) 86%, var(--fg-primary));
}

/* ---------- Drawer ----------
   A panel from the right edge for a task on one row, such as booking it or writing it up. The scrim behind it closes it,
   as Escape does; it sits where a modal does, above the page. A head, a body that scrolls, and a foot for its actions.
   <div class="ti-drawer-scrim" @click.self="close()" @keydown.escape.window="close()">
     <aside class="ti-drawer" role="dialog" aria-modal="true" aria-labelledby="…">
       <header class="ti-drawer-head">…</header><div class="ti-drawer-body">…</div><footer class="ti-drawer-foot">…</footer>
     </aside>
   </div> */
.ti-drawer-scrim {
    position: fixed;
    inset: 0;
    z-index: 1200;
    display: flex;
    justify-content: flex-end;
    background: var(--bg-overlay);
}
/* Its own size and colour: the framework's body sets neither, so a label left unclassed inside fell to the user
   agent's 16px black (measured on a switch's label, CA-382). */
.ti-drawer {
    display: flex;
    flex-direction: column;
    width: min(440px, 100vw);
    height: 100%;
    border-left: 1px solid var(--border-strong);
    background: var(--bg-app);
    color: var(--fg-primary);
    font-size: var(--fs-base);
}
/* Wider, for a panel whose fields hold sentences rather than choices: a list of goals scrolled out of
   view in a text field 172px wide at 440px (CA-437). Never wider than the window, as the drawer is not. */
.ti-drawer.wide {
    width: min(600px, 100vw);
}
.ti-drawer-head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 20px 24px 16px;
    border-bottom: 1px solid var(--border);
}
.ti-drawer-head-text { flex: 1 1 auto; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ti-drawer-eyebrow {
    font-size: var(--fs-xxs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--fg-tertiary);
}
.ti-drawer-title { margin: 0; font-family: var(--font-display); font-size: 23px; font-weight: 400; letter-spacing: -0.01em; }
.ti-drawer-sub { font-size: 12.5px; color: var(--fg-secondary); }
.ti-drawer-body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: 18px 24px;
    overflow: auto;
    /* A scroller, so it ends its own bounce in Edge as every scroller here does (CA-354). */
    overscroll-behavior: none;
}
.ti-drawer-foot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 24px;
    border-top: 1px solid var(--border);
}

/* ---------- Status pill, outline ----------
   A hairline and primary text, with the state on the dot alone, for a pill that sits on an identity card rather than
   in a list. A tone class on the pill colours the dot: <span class="ti-status-pill outline tone-accent">. */
.ti-status-pill.outline {
    background: transparent;
    color: var(--fg-primary);
    box-shadow: inset 0 0 0 1px var(--border);
}
.ti-status-pill.outline .dot {
    width: 7px;
    height: 7px;
    background: var(--tone, var(--fg-tertiary));
    transition: background-color 300ms;
}

/* ---------- Banner ----------
   A tinted strip that frames the task on a screen: the text, and an optional aside such as a meter. The tone class
   picks the tint, accent by default. The aside drops under the text when the row runs out of room. */
.ti-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-4) 28px;
    padding: 16px 20px;
    border-radius: var(--r-md);
    background: var(--tone-soft, var(--accent-soft));
}
.ti-banner-text { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.ti-banner-title { font-size: 14px; font-weight: 600; color: var(--fg-primary); }
.ti-banner-desc { font-size: var(--fs-base); line-height: 1.5; color: var(--fg-secondary); }
/* 360px: at 300 a 20% share was narrower than a long label and broke it in two (measured, CA-334). */
.ti-banner-aside { flex: 0 1 360px; min-width: 0; }

/* ---------- Keyboard key ---------- */
.ti-kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    box-sizing: border-box;
    border: 1px solid var(--border);
    border-bottom-width: 2px;
    border-radius: var(--r-xs);
    background: var(--bg-elevated, var(--bg-surface));
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    line-height: 1;
    color: var(--fg-secondary);
}

/* ---------- Sticky action bar ----------
   A long form's actions, stuck to the bottom of its scroller. */
.ti-action-bar {
    position: sticky;
    bottom: 0;
    z-index: 6;
    display: flex;
    align-items: center;
    gap: var(--s-4);
    padding: 14px var(--s-7);
    background: var(--bg-app);
    border-top: 1px solid var(--border);
}
.ti-action-bar-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 96px;
    font-size: var(--fs-sm);
    color: var(--fg-tertiary);
}
.ti-action-bar-actions { display: flex; align-items: center; gap: var(--s-2); margin-left: auto; }
/* The bar covers the bottom of the scroller it is stuck to, so whatever is brought into view there has to stop above
   it: a row the keys move to, a control Tab reaches. Measured on a graded list, a row stepped to sat under the 65px bar
   every time (CA-337). The padding goes on the scroller: a margin on the row is clipped by the card around it, which
   hides its overflow, so the last row of every card still sat under the bar. */
#ti-content:has( .ti-action-bar ) {
    scroll-padding-bottom: 96px;
}

/* ---------- Compact empty state for lists ---------- */
.ti-empty-state.inline {
    flex-direction: row;
    justify-content: flex-start;
    gap: var(--s-2);
    padding: var(--s-4) var(--s-5);
    text-align: left;
}
.ti-empty-state.inline .ti-empty-state-icon { width: 20px; height: 20px; }
.ti-empty-state.inline .ti-empty-state-title { font-size: var(--fs-base); font-weight: 500; }

/* ---------- Sidebar item counter ---------- */
.ti-sidebar-item-badge {
    margin-left: auto;
    min-width: 20px;
    height: 18px;
    padding: 0 6px;
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-pill);
    background: var(--sidebar-accent);
    color: var(--sidebar-accent-fg, var(--fg-primary));
    font-family: var(--font-mono);
    font-size: 10.5px;
    font-weight: 600;
}
.ti-application.collapsed .ti-sidebar-item-badge {
    position: absolute;
    top: 5px;
    right: 7px;
    min-width: 8px;
    width: 8px;
    height: 8px;
    padding: 0;
    font-size: 0;
}
