/* ==========================================================================
   Cuadro Compass — stylesheet
   Plain CSS. No framework, no inline styles, no animations.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Fonts
   -------------------------------------------------------------------------- */

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/inter-400.woff2') format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/inter-500.woff2') format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/inter-600.woff2') format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/inter-700.woff2') format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 800;
    font-display: swap;
    src: url('../fonts/inter-800.woff2') format('woff2');
}

/* --------------------------------------------------------------------------
   2. Design tokens
   -------------------------------------------------------------------------- */

:root {
    --bg: #f0f4f8;
    --bg-alt: #e2e8f0;
    --surface: #ffffff;
    --surface-muted: #f8fafc;
    --panel: rgba(255, 255, 255, 0.6);
    --panel-alt: rgba(241, 245, 249, 0.4);
    --border: rgba(255, 255, 255, 0.6);
    --border-solid: #e2e8f0;
    --border-strong: #cbd5e1;

    --text: #334155;
    --text-strong: #1e293b;
    --text-dark: #0f172a;
    --text-secondary: #64748b;
    --text-muted: #94a3b8;
    --brand: #131c2f;

    --blue: #2563eb;
    --blue-soft: #dbeafe;
    --blue-text: #1d4ed8;
    --green: #059669;
    --green-soft: #d1fae5;
    --green-text: #047857;
    --amber: #d97706;
    --amber-soft: #fef3c7;
    --amber-text: #b45309;
    --rose: #e11d48;
    --rose-soft: #ffe4e6;
    --rose-text: #be123c;
    --indigo: #4f46e5;
    --indigo-soft: #e0e7ff;
    --indigo-text: #4338ca;
    --slate-soft: #f1f5f9;

    --shadow-soft: 0 10px 40px -10px rgba(148, 163, 184, 0.15);
    --shadow-panel: 0 20px 40px -10px rgba(19, 28, 47, 0.08),
                    inset 0 1px 0 rgba(255, 255, 255, 0.8);
    --shadow-sidebar: 0 20px 50px rgba(19, 28, 47, 0.08);
    --shadow-float: 0 25px 50px -12px rgba(19, 28, 47, 0.15);

    /* One radius for every rounded rectangle. Circles use 50% and pills use
       --radius-pill; nothing else varies. */
    --radius: 16px;
    --radius-pill: 999px;

    /* One height for every control a finger or a pointer aims at — buttons,
       pills, inputs, selects, menu rows — so a row of them lines up without
       each being nudged into place. Padding is vertical-free on these: the
       height sets it, and `line-height` centres the text inside. */
    --control-h: 32px;
    --pad: 16px;

    --sidebar-w-min: 200px;
    --sidebar-w-max: 340px;
    --sidebar-w-collapsed: 76px;
}

/* --------------------------------------------------------------------------
   3. Reset & base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    height: 100vh;
    display: flex;
    overflow: hidden;
    /* Anchors the absolutely positioned global search. */
    position: relative;
    font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, sans-serif;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text);
    background-color: var(--bg);
    background-image:
        radial-gradient(circle at 0% 0%, rgba(226, 232, 240, 0.6) 0%, transparent 40%),
        radial-gradient(circle at 100% 0%, rgba(203, 213, 225, 0.5) 0%, transparent 40%),
        radial-gradient(circle at 100% 100%, rgba(241, 245, 249, 0.5) 0%, transparent 40%),
        linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
    background-attachment: fixed;
}

body::selection,
::selection {
    background: var(--bg-alt);
    color: var(--text-dark);
}

h1, h2, h3, h4, h5, h6 {
    margin: 0;
    font-weight: 700;
    color: var(--text-dark);
}

p {
    margin: 0;
}

ul, ol {
    margin: 0;
    padding: 0;
}

a {
    color: inherit;
    text-decoration: none;
}

button {
    font-family: inherit;
    font-size: inherit;
    color: inherit;
    background: none;
    border: 0;
    cursor: pointer;
}

table {
    width: 100%;
    border-collapse: collapse;
}

/* --------------------------------------------------------------------------
   4. Icons (SVG sprite)
   -------------------------------------------------------------------------- */

/* Every svg in the app is an icon from the sprite, so the tag carries the
   sizing rather than a class repeating what the tag already says. */
svg {
    width: 1em;
    height: 1em;
    fill: currentColor;
    flex-shrink: 0;
    vertical-align: -0.125em;
}

.icon-lg { width: 1.5em; height: 1.5em; }

/* --------------------------------------------------------------------------
   5. Layout
   -------------------------------------------------------------------------- */

.sidebar-container {
    height: 100vh;
    flex-shrink: 0;
    padding: 16px 0 16px 16px;
    z-index: 50;
}

.sidebar {
    width: max-content;
    min-width: var(--sidebar-w-min);
    max-width: var(--sidebar-w-max);
    height: calc(100vh - 32px);
    display: flex;
    flex-direction: column;
    position: relative;
    background: linear-gradient(180deg, rgba(248, 250, 252, 0.8) 0%, rgba(241, 245, 249, 0.6) 100%);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sidebar);
}

main {
    flex: 1;
    width: 100%;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    position: relative;
    z-index: 0;
    padding: var(--pad);
    border-radius: var(--radius);
}

/* A scrolling box drops its bottom padding once the content overflows, so the
   last row would end flush against the edge. This puts the space back as part
   of the content, where scrolling cannot eat it. */
main::after {
    content: "";
    display: block;
    flex: 0 0 var(--pad);
}

/* No scrollbars anywhere. Everything still scrolls — wheel, keyboard, touch,
   drag — only the bar is not drawn. `scrollbar-width` is what Firefox reads;
   the pseudo-element covers the rest. Applied to everything rather than to a
   list of regions, so a scrolling area added later needs no reminder. */
* {
    scrollbar-width: none;
}

*::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
}

/* --------------------------------------------------------------------------
   6. Sidebar
   -------------------------------------------------------------------------- */

.sidebar-toggle {
    position: absolute;
    top: 40px;
    right: -18px;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    color: var(--text-muted);
    background: var(--surface);
    border: 1px solid var(--slate-soft);
    border-radius: 50%;
    box-shadow: var(--shadow-soft);
    z-index: 50;
}

.sidebar-toggle:hover {
    color: var(--text-strong);
}

.sidebar-body {
    flex: 1;
    min-height: 0;
    padding: 0 14px 12px;
    overflow-y: auto;
    overflow-anchor: none;
}

.sidebar-logo {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
    padding: 22px 20px 18px;
    overflow: hidden;
}

.sidebar-logo-mark {
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 18px;
    color: var(--text-strong);
    background: linear-gradient(135deg, #ffffff 0%, var(--surface-muted) 100%);
    border: 1px solid var(--surface);
    border-radius: var(--radius);
    box-shadow: var(--shadow-soft);
}

.sidebar-logo-title {
    display: block;
    font-size: 19px;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1.15;
    color: var(--text-dark);
}

.nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.nav-group-label {
    margin: 16px 0 4px;
    padding: 0 16px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: var(--text-muted);
}

.nav-item {
    display: flex;
    align-items: center;
    gap: 12px;
    align-self: stretch;
    height: var(--control-h);
    padding: 10px 16px;
    font-size: 13.5px;
    font-weight: 500;
    color: var(--text-secondary);
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
}

.nav-item:hover {
    color: var(--brand);
    background: rgba(255, 255, 255, 0.6);
    border-color: rgba(255, 255, 255, 0.5);
    box-shadow: 0 4px 15px rgba(19, 28, 47, 0.05);
}

.nav-item.active {
    font-weight: 700;
    color: var(--brand);
    background: linear-gradient(135deg, #ffffff 0%, var(--slate-soft) 100%);
    border-color: rgba(255, 255, 255, 0.8);
    box-shadow: 0 8px 20px rgba(19, 28, 47, 0.08),
                inset 0 1px 0 rgba(255, 255, 255, 1);
}

.nav-item svg {
    width: 20px;
    font-size: 16px;
}

/* User block */

.user-menu-container {
    position: relative;
    flex-shrink: 0;
    margin: 0 10px 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border-solid);
}

.user-profile {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-width: 0;
    padding: 10px;
    text-align: left;
    overflow: hidden;
    border: 1px solid transparent;
    border-radius: var(--radius);
}

.user-profile:hover {
    background: rgba(255, 255, 255, 0.4);
    border-color: rgba(255, 255, 255, 0.5);
}

.user-avatar {
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 12px;
    font-weight: 700;
    color: #ffffff;
    background: linear-gradient(135deg, var(--brand) 0%, #334155 100%);
    border: 1px solid var(--border);
    border-radius: 50%;
}

.user-meta {
    flex: 1;
    min-width: 0;
    max-width: 150px;
    overflow: hidden;
}

.user-name {
    display: block;
    font-size: 14px;
    font-weight: 700;
    color: var(--text-strong);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user-role {
    display: block;
    font-size: 10px;
    font-weight: 500;
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user-menu-popup {
    position: absolute;
    bottom: 0;
    left: 100%;
    margin-left: 12px;
    width: 240px;
    padding: 8px;
    display: none;
    flex-direction: column;
    gap: 4px;
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
    box-shadow: var(--shadow-float);
    z-index: 60;
}

.user-menu-popup.open {
    display: flex;
}

.user-menu-item {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 12px 16px;
    font-size: 12px;
    font-weight: 700;
    color: var(--text-secondary);
    text-align: left;
    border-radius: var(--radius);
}

.user-menu-item:hover {
    background: var(--surface-muted);
}

/* Signing out is the one entry here that ends something, so it is the one
   that is red. The others are ordinary navigation and read as such. */
.user-menu-item[type="submit"] {
    color: var(--rose);
}

.user-menu-item[type="submit"]:hover {
    background: var(--rose-soft);
}

.user-menu-item form {
    display: contents;
}

/* Collapsed state */

.sidebar.collapsed {
    width: var(--sidebar-w-collapsed);
    min-width: var(--sidebar-w-collapsed);
    max-width: var(--sidebar-w-collapsed);
}

.sidebar.collapsed .sidebar-text {
    display: none;
}

.sidebar.collapsed .sidebar-body,
.sidebar.collapsed .nav-item,
.sidebar.collapsed .user-profile {
    padding-left: 0;
    padding-right: 0;
    justify-content: center;
}

.sidebar.collapsed .nav {
    align-items: center;
}

/* The "Other" label is hidden when collapsed; a rule stands in for it. */
.sidebar.collapsed .nav-group-label.sidebar-text {
    display: block;
    width: 24px;
    height: 1px;
    margin: 10px 0;
    padding: 0;
    overflow: hidden;
    text-indent: -999px;
    background: var(--border-solid);
}

.sidebar.collapsed .sidebar-logo {
    padding: 18px 0 14px;
    justify-content: center;
}

.sidebar.collapsed .sidebar-logo-mark {
    width: 38px;
    height: 38px;
    font-size: 17px;
}

/* A fixed-width pill inside a padded column sits wherever the padding leaves
   it, which is off-centre. Centring it in the track puts every icon on the
   sidebar's own axis. */
.sidebar.collapsed .nav-item {
    width: 44px;
    align-self: center;
}

.sidebar.collapsed .user-menu-popup {
    width: 200px;
}

/* --------------------------------------------------------------------------
   7. Panels & cards
   -------------------------------------------------------------------------- */

.panel {
    background: linear-gradient(135deg, var(--panel) 0%, var(--panel-alt) 100%);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-panel);
}


.panel-pad {
    padding: 24px;
}

.card {
    padding: 20px;
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
}

/* One block of the page followed by another: the tag carries the gap, so a new
   section is spaced without remembering a class. `+` rather than a bottom
   margin on every section, so the last one does not push the page taller. */
main > section + section,
main > section + div,
main > div + section,
main > * + footer {
    margin-top: var(--pad);
}

.panel-head {
    padding-right: 20px;
}

/* The pagination bar every paged table gets. It sits under the table inside
   the same panel, so it carries the top rule rather than a box of its own:
   what is being paged is the thing directly above it. */
.pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pad);
    padding: var(--pad);
    font-size: 13px;
    color: var(--text-muted);
    border-top: 1px solid var(--border-solid);
}

/* The page buttons group at the right; the count stays left. */
.pager nav {
    display: flex;
    align-items: center;
    gap: 4px;
}

.pager button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--control-h);
    height: var(--control-h);
    padding: 0 10px;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
    cursor: pointer;
}

.pager button:hover:not(:disabled) {
    color: var(--text-strong);
    background: var(--surface-muted);
}

/* The page you are on is not a place you can go, so it reads as a label
   rather than a button, even though it is one. */
.pager button[aria-current="page"] {
    color: var(--surface);
    background: var(--text-strong);
    border-color: var(--text-strong);
}

.pager button:disabled {
    opacity: 0.4;
    cursor: default;
}

/* A gap in the run of page numbers. */
.pager span[aria-hidden] {
    padding: 0 4px;
}

/* A table that loads its own rows says so while it is doing it, instead of
   flashing an empty body. */
tbody[aria-busy="true"] {
    opacity: 0.4;
}

/* --------------------------------------------------------------------------
   Sortable table headers
   -------------------------------------------------------------------------- */

/* A header that sorts is a button in every way but the tag, so it takes the
   affordances of one. The arrow only appears once a column is actually the
   one being sorted by, so the row of headers stays quiet. */
main table th[data-sort] {
    cursor: pointer;
    user-select: none;
}

main table th[data-sort]:hover {
    color: var(--text-strong);
}

main table th[data-sort]::after {
    content: "";
    margin-left: 6px;
    font-size: 9px;
    /* Holds the arrow's width while it is absent, so the header does not
       shift when a column becomes the sorted one. */
    display: inline-block;
    width: 7px;
}

main table th[aria-sort="ascending"]::after {
    content: "\2191";
}

main table th[aria-sort="descending"]::after {
    content: "\2193";
}

main table th[aria-sort] {
    color: var(--text-strong);
}

/* --------------------------------------------------------------------------
   8. Page header
   -------------------------------------------------------------------------- */

main > header {
    display: flex;
    align-items: center;
    /* Pages carry no title: an actions-only head sits flush right. */
    justify-content: flex-end;
    gap: 12px;
    margin-bottom: var(--pad);
}

/* Detail pages still lead with the record identity, and their actions group
   on the right instead of sitting in the flow. */
main > header:has(h1) {
    align-items: flex-start;
    gap: 24px;
    justify-content: space-between;
}

main > header h1 {
    font-size: 34px;
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--text-dark);
}

main > header h1 + p {
    margin-top: 4px;
    font-size: 15px;
    color: var(--text-secondary);
}

main > header > div:last-child {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   9. Buttons
   -------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    height: var(--control-h);
    padding: 0 var(--pad);
    font-size: 13px;
    font-weight: 700;
    color: var(--text-strong);
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-soft);
}

.btn:hover {
    border-color: var(--border-strong);
}

.btn-primary {
    color: #ffffff;
    background: linear-gradient(135deg, var(--brand) 0%, var(--text-strong) 100%);
    border-color: transparent;
}

.btn-primary:hover {
    background: linear-gradient(135deg, #0b1220 0%, var(--brand) 100%);
}

.btn-block {
    width: 100%;
}

.btn-icon {
    padding: 0;
    width: var(--control-h);
    height: var(--control-h);
    color: var(--text-muted);
    box-shadow: none;
    background: transparent;
    border-color: transparent;
}

.btn-icon:hover {
    color: var(--text-strong);
    background: var(--surface);
}

.btn-danger {
    color: var(--rose);
    background: transparent;
    border-color: transparent;
    box-shadow: none;
}

.btn-danger:hover {
    background: var(--rose-soft);
}

/* --------------------------------------------------------------------------
   10. Forms
   -------------------------------------------------------------------------- */

/* Every label in a panel or a form row is a field label. `.sr-only` still
   wins where a label is there only for a screen reader. */
.field-row label,
.side-panel label,
main form label {
    display: block;
    margin-bottom: 8px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: var(--text-muted);
}

/* Anything you can type in or pick from, styled on the element rather than on
   a class: a control is a control whether or not somebody remembered to write
   class="field" on it.
 *
 * Solid white, with a grey border. Both were translucent white before — 50%
 * over a #f0f4f8 page, which came out very nearly the page colour with a
 * border nobody could see. The select on the tasks page was the worst of it:
 * a filter that did not look like anything you could click. A control has to
 * announce itself, so the background is opaque and the border is real. */
input[type="text"],
input[type="password"],
input[type="email"],
input[type="number"],
input[type="date"],
input[type="search"],
input[type="tel"],
input[type="url"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"],
input:not([type]),
select,
textarea {
    width: 100%;
    padding: 0 var(--pad);
    height: var(--control-h);
    line-height: var(--control-h);
    font-family: inherit;
    font-size: 14px;
    color: var(--text);
    background-color: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: inset 0 2px 4px rgba(148, 163, 184, 0.05);
}

/* Hovering says "this one is live" before the click, which is the other half
   of the problem the flat background caused. */
input:hover:not(:disabled):not([type="checkbox"]):not([type="radio"]),
select:hover:not(:disabled),
textarea:hover:not(:disabled) {
    border-color: var(--text-muted);
}

input:focus,
select:focus,
textarea:focus {
    outline: none;
    background-color: var(--surface);
    border-color: var(--text-muted);
    box-shadow: 0 8px 20px rgba(19, 28, 47, 0.08),
                inset 0 0 0 1px var(--text-muted);
}

/* Tick boxes are not text fields: the rule above would stretch one to the
   width of its row. They are listed here rather than excluded above so the
   exemption is visible next to the rule it exempts them from. */
input[type="checkbox"],
input[type="radio"] {
    width: auto;
    height: auto;
    padding: 0;
    line-height: normal;
    box-shadow: none;
}

/* A field nobody may edit should look it, rather than looking live and
   refusing to take a keystroke. */
input:disabled,
select:disabled,
textarea:disabled,
input[readonly],
textarea[readonly] {
    background-color: var(--surface-muted);
    color: var(--text-muted);
    cursor: not-allowed;
}

input::placeholder,
textarea::placeholder {
    color: var(--text-muted);
}

select {
    appearance: none;
    padding-right: 40px;
    /* background-image only, never the `background` shorthand: that would
       reset the colour set above and put the page back through the control. */
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2364748b' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
    background-position: right 12px center;
    background-repeat: no-repeat;
    background-size: 1.2em 1.2em;
}

textarea {
    resize: vertical;
}

/* Global search — sits in the sidebar, above the nav. It follows the sidebar
   width instead of floating over the page, so it costs no room on the right. */

.search {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 4px;
    margin: 0 14px 10px;
    height: var(--control-h);
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-soft);
    overflow: hidden;
}

.search:focus-within {
    border-color: var(--border-strong);
}

.search-toggle {
    width: var(--control-h);
    height: var(--control-h);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--text-secondary);
}

.search:hover .search-toggle,
.search:focus-within .search-toggle {
    color: var(--text-dark);
}

.search input {
    width: 100%;
    min-width: 0;
    padding: 0 16px 0 0;
    font-size: 13px;
    background: transparent;
    border: 0;
    box-shadow: none;
    border-radius: 0;
}

.search input:focus {
    background: transparent;
    border: 0;
    box-shadow: none;
    outline: none;
}

/* Collapsed sidebar: the field goes, the icon stays as the click target. */
.sidebar.collapsed .search {
    width: 44px;
    margin-left: auto;
    margin-right: auto;
    justify-content: center;
}

/* --------------------------------------------------------------------------
   11. Tables
   -------------------------------------------------------------------------- */

/* Every table fills the width it is given and lays out its own columns. It is
   never narrower than its container, and never wider: `fixed` shares the room
   between the columns instead of sizing them from their content. */
.panel > table,
main > table,
table {
    width: 100%;
    max-width: 100%;
    table-layout: fixed;
}

/* Cell text that will not fit is cut rather than pushing the row taller. */
main table td {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Inside a panel the first and last cell line up with the heading, so a table
   reads as part of the panel rather than a thing dropped into it. */
.panel table th:first-child,
.panel table td:first-child {
    padding-left: 24px;
}

.panel table th:last-child,
.panel table td:last-child {
    padding-right: 24px;
}

main table th {
    padding: 0 10px;
    height: var(--control-h);
    font-size: 10px;
    font-weight: 700;
    text-align: left;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--text-muted);
    white-space: nowrap;
}

main table td {
    padding: 0 10px;
    height: var(--control-h);
    font-size: 14px;
    border-top: 1px solid var(--border-solid);
    vertical-align: middle;
}

main table tbody tr:hover td {
    background: rgba(255, 255, 255, 0.5);
}

main table .col-right {
    text-align: right;
}

main table td {
    color: var(--text-secondary);
}

.cell-strong {
    font-weight: 600;
    color: var(--text-strong);
}

/* --------------------------------------------------------------------------
   12. Badges & pills
   -------------------------------------------------------------------------- */

.badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    /* Not --control-h: a badge sits inside a 32px cell, so it has to be
       smaller than the box holding it. */
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    border-radius: var(--radius);
    white-space: nowrap;
}

.badge-blue   { color: var(--blue-text);   background: var(--blue-soft); }
.badge-amber  { color: var(--amber-text);  background: var(--amber-soft); }
.badge-indigo { color: var(--indigo-text); background: var(--indigo-soft); }

.badge-upper {
    text-transform: uppercase;
}

.count-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    font-size: 10px;
    font-weight: 700;
    color: #ffffff;
    background: var(--rose);
    border-radius: var(--radius-pill);
}

.dot-online {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--green);
    flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   13. Section labels & breadcrumb
   -------------------------------------------------------------------------- */

/* A row of controls under a panel's table. Not `.pager`: that one exists to
   turn pages and centres a count, where this holds a name to type and the
   buttons that act on it, which must not be squeezed onto two lines. */
.panel-foot {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 24px;
    border-top: 1px solid var(--border-solid);
}

/* The name is the only part that should grow. */
.panel-foot .field {
    flex: 1;
    min-width: 200px;
}

/* A button here says what it does and needs the room to say it. */
.panel-foot .btn {
    white-space: nowrap;
}

/* A panel that holds a table has no padding of its own — the table has to
   reach the edges — so the prose around it takes its own, matching the
   heading's. Without this a paragraph sits flush against the border while the
   heading above it does not. */
.panel > p {
    padding: 0 24px 16px;
}

.panel h2,
.side-panel h2 {
    padding: 20px 24px 12px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: var(--text-muted);
}

main > nav {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 20px;
    font-size: 13px;
    color: var(--text-secondary);
}


/* --------------------------------------------------------------------------
   14. KPI tiles
   -------------------------------------------------------------------------- */

.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 20px;
    margin-bottom: 28px;
}

.kpi {
    padding: 24px 28px;
}

.kpi figcaption {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: var(--text-secondary);
}

.kpi > p {
    margin-top: 8px;
    font-size: 32px;
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--text-dark);
}

/* --------------------------------------------------------------------------
   15. Tabs
   -------------------------------------------------------------------------- */

.tabs {
    display: flex;
    align-items: center;
    gap: 32px;
    margin-bottom: 24px;
    border-bottom: 1px solid var(--border-solid);
}

.tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: var(--control-h);
    padding: 0 2px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-secondary);
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.tab:hover {
    color: var(--text-strong);
}

.tab.active {
    font-weight: 700;
    color: var(--text-dark);
    border-bottom-color: var(--text-dark);
}

/* --------------------------------------------------------------------------
   16. Files page
   -------------------------------------------------------------------------- */

.folder-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 20px;
    padding: 0 24px 24px;
}

.folder-card {
    padding: 20px;
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
}

.folder-icon {
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 20px;
    font-size: 18px;
    border-radius: var(--radius);
}

.folder-name {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-strong);
}

.folder-meta {
    margin-top: 4px;
    font-size: 12px;
    color: var(--text-secondary);
}

.file-icon {
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 14px;
    border-radius: var(--radius);
}


.file-name-cell {
    display: flex;
    align-items: center;
    gap: 14px;
}

/* --------------------------------------------------------------------------
   17. Chat page
   -------------------------------------------------------------------------- */

.chat-layout {
    display: grid;
    grid-template-columns: 320px 1fr;
    gap: 24px;
    align-items: start;
}

.chat-sidebar {
    padding: 20px;
}

.channel-list {
    list-style: none;
    margin-top: 8px;
}

.channel-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    font-size: 14px;
    color: var(--text-secondary);
    border-radius: var(--radius);
}

.channel-item:hover {
    background: rgba(255, 255, 255, 0.6);
}

.channel-item.active {
    font-weight: 700;
    color: var(--text-dark);
    background: var(--surface);
}

.channel-hash {
    color: var(--text-muted);
}

.channel-name {
    flex: 1;
}

.dm-avatar {
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 9px;
    font-weight: 700;
    color: var(--text-secondary);
    background: var(--slate-soft);
    border-radius: 50%;
}

.chat-main {
    display: flex;
    flex-direction: column;
    min-height: 640px;
}

.chat-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    padding: 22px 26px;
    border-bottom: 1px solid var(--border-solid);
}

.chat-title {
    font-size: 17px;
    font-weight: 700;
    color: var(--text-dark);
}

.chat-topic {
    margin-top: 2px;
    font-size: 13px;
    color: var(--text-secondary);
}

.chat-head-actions {
    display: flex;
    align-items: center;
    gap: 4px;
}

.chat-messages {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 22px;
    padding: 26px;
    overflow-y: auto;
}

.message {
    display: flex;
    gap: 14px;
}

.message-avatar {
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 11px;
    font-weight: 700;
    color: #ffffff;
    border-radius: 50%;
}


.message-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 3px;
}

.message-author {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-strong);
}

.message-time {
    font-size: 11px;
    color: var(--text-muted);
}

.message-text {
    font-size: 14px;
    color: var(--text);
}

.chat-composer {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 18px 26px;
    border-top: 1px solid var(--border-solid);
}

.chat-composer input {
    flex: 1;
    border-radius: var(--radius-pill);
}

.composer-send {
    width: 42px;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: #ffffff;
    background: var(--brand);
    border-radius: 50%;
}

/* --------------------------------------------------------------------------
   18. Notes page
   -------------------------------------------------------------------------- */

.notes-layout {
    display: grid;
    grid-template-columns: 380px 1fr;
    gap: 24px;
    align-items: start;
}

.notes-list {
    padding: 20px;
}

.notes-filters {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 16px 0 8px;
}

.chip {
    display: inline-flex;
    align-items: center;
    height: var(--control-h);
    padding: 0 var(--pad);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    border-radius: var(--radius-pill);
}

.chip:hover {
    background: rgba(255, 255, 255, 0.6);
}

.chip.active {
    font-weight: 700;
    color: #ffffff;
    background: var(--brand);
}

.note-item {
    display: block;
    padding: 16px;
    border-top: 1px solid var(--border-solid);
}

.note-item:first-of-type {
    border-top: 0;
}

.note-item:hover {
    background: rgba(255, 255, 255, 0.5);
}

.note-item.active {
    background: var(--surface);
    border-radius: var(--radius);
}

.note-item-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.note-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-strong);
}

.note-preview {
    margin-top: 4px;
    font-size: 13px;
    color: var(--text-secondary);
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.note-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 10px;
    font-size: 11px;
    color: var(--text-muted);
}

.note-pin {
    color: var(--amber);
}

.note-editor {
    min-height: 640px;
    display: flex;
    flex-direction: column;
}

.editor-toolbar {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border-solid);
}

.spacer {
    flex: 1;
}

.editor-divider {
    width: 1px;
    height: 20px;
    margin: 0 8px;
    background: var(--border-solid);
}

.editor-body {
    padding: 32px 40px;
}

.editor-title {
    font-size: 30px;
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--text-dark);
}

.editor-meta {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 10px;
    font-size: 12px;
    color: var(--text-muted);
}

.editor-content {
    margin-top: 28px;
    font-size: 15px;
    line-height: 1.7;
}

.editor-content h2 {
    margin: 28px 0 12px;
    font-size: 18px;
}

.editor-content ul {
    padding-left: 22px;
    list-style: disc;
}

.editor-content li {
    margin-bottom: 8px;
}

.editor-content p + p {
    margin-top: 12px;
}

/* --------------------------------------------------------------------------
   19. Login page
   -------------------------------------------------------------------------- */

.login-body {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    overflow: auto;
}

.login-card {
    width: 100%;
    max-width: 440px;
    padding: 40px;
}

.login-head {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 40px;
}

.login-field {
    margin-bottom: 24px;
}

.login-error {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 24px;
    font-size: 12px;
    font-weight: 700;
    color: var(--rose);
}

.login-submit {
    margin-top: 8px;
    padding: 16px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.15em;
}

/* --------------------------------------------------------------------------
   20. Empty state
   -------------------------------------------------------------------------- */

main figure,
.empty {
    padding: 80px 24px;
    text-align: center;
}

main figure svg,
.empty svg {
    font-size: 34px;
    color: var(--text-muted);
}

main figure > p:first-of-type {
    margin-top: 18px;
    font-size: 17px;
    font-weight: 700;
    color: var(--text-strong);
}

main figure > p:last-of-type {
    margin-top: 6px;
    font-size: 14px;
    color: var(--text-secondary);
}

/* --------------------------------------------------------------------------
   21. Utilities
   -------------------------------------------------------------------------- */

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.row      { display: flex; align-items: center; gap: 12px; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.spacer   { flex: 1; }
.nowrap   { white-space: nowrap; }
.text-muted { color: var(--text-secondary); }
.text-faint { color: var(--text-muted); }

/* --------------------------------------------------------------------------
   22. Mobile navigation
   -------------------------------------------------------------------------- */

/* A bar at the top of the screen holding the hamburger, and nothing else.
   Both it and the scrim are desktop-hidden; the media query turns them on. */
.mobile-bar {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 70;
    align-items: center;
    padding: 8px 12px calc(8px + env(safe-area-inset-top));
    background: rgba(255, 255, 255, 0.95);
    border-bottom: 1px solid var(--border);
}

.mobile-scrim {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 65;
    background: rgba(15, 23, 42, 0.4);
}

/* --------------------------------------------------------------------------
   23. Toolbar & view switch
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   24. Kanban board
   -------------------------------------------------------------------------- */

/* The board takes the height left in the page rather than growing past it, so
   a column full of cards scrolls inside its own column instead of scrolling
   the whole page and dragging every other column's header out of sight.
   `min-height: 0` is what lets a flex child actually shrink to that. */
.board {
    display: flex;
    gap: 16px;
    /* Each column is as tall as its own cards, never stretched to match the
       fullest one — an empty column drawn full height is just a tall empty
       box. The ceiling is the board itself, set below. */
    align-items: flex-start;
    overflow-x: auto;
    padding-bottom: 12px;
    flex: 1;
    min-height: 0;
}

/* Equal shares of the row, never narrower than 200px. `flex: 1 1 200px` gives
   every column the same basis and the same right to grow, so they widen
   together to fill the board and stop at the edge. When the minimum cannot be
   met for all of them the row scrolls instead of squeezing them thinner. */
.board-column {
    flex: 1 1 200px;
    min-width: 200px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    /* As tall as its cards, up to the height of the board; past that the head
       stays put and the cards scroll under it. `align-items: flex-start` on
       the board is what keeps a short column short, and `100%` of a flex
       container whose own height is settled resolves to that height. */
    min-height: 0;
    max-height: 100%;
    background: rgba(255, 255, 255, 0.45);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.board-column-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 4px;
    width: 100%;
    text-align: left;
}

.board-column-cards {
    display: flex;
    flex-direction: column;
    gap: 12px;
    /* The cards are the part that scrolls; the bar itself is hidden by the
       global rule, so the column just slides. `flex: 0 1 auto` rather than
       `1`: the area takes the room its cards need and gives it back when
       there are few, instead of claiming the whole column. */
    overflow-y: auto;
    flex: 0 1 auto;
    /* A column with no cards still has to be droppable. `:empty` will not do
       it — the template leaves whitespace inside the element — and a box of
       zero height catches no pointer, so the area keeps a height of its own. */
    min-height: 60px;
}

.board-column-chevron {
    color: var(--text-muted);
    transform: rotate(-90deg);
}

/* Collapsed: the column becomes a narrow vertical strip so more stages fit on
   screen at once. The head is turned on its side and reads bottom-to-top; the
   cards are gone, only the count stays. */
/* A collapsed column keeps its strip width and gives its share to the others. */
.board-column.collapsed {
    flex: 0 0 52px;
    min-width: 52px;
    padding: 16px 8px;
}

.board-column.collapsed .board-column-cards {
    display: none;
}

.board-column.collapsed .board-column-head {
    flex-direction: column;
    gap: 12px;
    padding: 0;
    height: 100%;
    justify-content: flex-start;
}

.board-column.collapsed .badge {
    writing-mode: vertical-rl;
    /* vertical-rl reads top-to-bottom; the extra turn puts it bottom-to-top,
       which is the usual direction for a sideways label. */
    transform: rotate(180deg);
    padding: 10px 4px;
}

.board-column.collapsed .spacer {
    flex: 0;
}

.board-column.collapsed .board-column-chevron {
    transform: rotate(90deg);
    order: -1;
}


.board-count {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
}

.board-card {
    display: block;
    padding: 14px;
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
    box-shadow: var(--shadow-soft);
}

.board-card:hover {
    border-color: var(--border-strong);
}

.board-card-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}

.board-card-title {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-strong);
}

.board-card-sub {
    font-size: 12px;
    color: var(--text-secondary);
}

.board-card-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 12px;
    font-size: 11px;
    color: var(--text-muted);
}

.mini-avatar {
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 10px;
    font-weight: 700;
    color: #ffffff;
    border-radius: 50%;
}

/* --------------------------------------------------------------------------
   25. Progress bar
   -------------------------------------------------------------------------- */

/* Five bands laid side by side, always in this order: tested, done but
   unchecked, still open, unclear, parked. They are drawn in sequence rather
   than stacked, so the widths add up to the whole and each colour shows the
   size of its own share. */
.progress {
    height: 6px;
    display: flex;
    background: var(--slate-soft);
    border-radius: var(--radius-pill);
    overflow: hidden;
}

.progress > span {
    height: 100%;
    /* Widths are set by the progress-N classes; nothing may grow past its own
       share, and a band rounded to a sliver must not be squeezed to nothing. */
    flex: 0 0 auto;
}

.band-tested   { background: var(--text-dark); }
.band-untested { background: var(--text-muted); }
/* "Still open" is the empty part of the bar: the track already shows it. */
.band-pending  { background: transparent; }
.band-unclear  { background: var(--amber); }
.band-on-hold  { background: var(--rose); }

/* Fill widths in 5% steps — inline styles are not allowed, so the value is
   rounded to the nearest step and picked up as a class. */
.progress-0   { width: 0; }
.progress-5   { width: 5%; }
.progress-10  { width: 10%; }
.progress-15  { width: 15%; }
.progress-20  { width: 20%; }
.progress-25  { width: 25%; }
.progress-30  { width: 30%; }
.progress-35  { width: 35%; }
.progress-40  { width: 40%; }
.progress-45  { width: 45%; }
.progress-50  { width: 50%; }
.progress-55  { width: 55%; }
.progress-60  { width: 60%; }
.progress-65  { width: 65%; }
.progress-70  { width: 70%; }
.progress-75  { width: 75%; }
.progress-80  { width: 80%; }
.progress-85  { width: 85%; }
.progress-90  { width: 90%; }
.progress-95  { width: 95%; }
.progress-100 { width: 100%; }

.progress-row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 140px;
}

.progress-row .progress {
    flex: 1;
}

.progress-value {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    min-width: 34px;
    text-align: right;
}

/* --------------------------------------------------------------------------
   26. Detail layout
   -------------------------------------------------------------------------- */

.detail-layout {
    display: grid;
    grid-template-columns: 1fr 320px;
    gap: 24px;
    align-items: start;
}

.detail-section + .detail-section {
    margin-top: 20px;
}

.panel ul {
    list-style: none;
}

/* A detail card is a list of definitions, so it is written as one. The grid
   keeps every term in the same column without a wrapper per pair. */
.panel dl {
    display: grid;
    grid-template-columns: 120px 1fr;
    gap: 10px 16px;
    margin: 0;
}

.panel dt {
    color: var(--text-secondary);
}

.panel dd {
    margin: 0;
    color: var(--text-strong);
    font-weight: 500;
    word-break: break-word;
}

/* Sequence strip */

.sequence {
    display: flex;
    align-items: stretch;
    gap: 8px;
    overflow-x: auto;
    padding-bottom: 4px;
}

.sequence-step {
    flex: 1;
    min-width: 96px;
    padding: 14px 12px;
    text-align: center;
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
}

.sequence-step.done {
    background: var(--green-soft);
    border-color: transparent;
}

.sequence-step.current {
    border-color: var(--brand);
    box-shadow: 0 0 0 1px var(--brand) inset;
}

.sequence-day {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-muted);
}

.sequence-channel {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin-top: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-strong);
}

/* On the leads page the sequence is a footnote rather than a strip of cards:
   the tag says which of the two it is, so neither needs a class of its own. */
main > footer.sequence {
    display: block;
    padding: 0 var(--pad);
    font-size: 12px;
    color: var(--text-muted);
}

/* Timeline */

.timeline {
    list-style: none;
}

.timeline li {
    display: flex;
    gap: 14px;
    padding: 14px 0;
    border-top: 1px solid var(--border-solid);
}

.timeline li:first-child {
    border-top: 0;
}

.timeline-icon {
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 12px;
    color: var(--text-secondary);
    background: var(--slate-soft);
    border-radius: 50%;
}

.timeline-when {
    font-size: 11px;
    color: var(--text-muted);
}

.timeline-what {
    font-size: 13px;
    color: var(--text-strong);
}

/* Message rows on the lead detail */

.msg-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 0;
    border-top: 1px solid var(--border-solid);
}

.msg-row:first-of-type {
    border-top: 0;
}

.msg-row.inbound .msg-subject {
    font-weight: 700;
    color: var(--text-dark);
}

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

.msg-subject {
    font-size: 13px;
    color: var(--text-strong);
}

.msg-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    font-size: 11px;
    color: var(--text-muted);
}

/* Mockup notice */

.mock-note {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 20px;
    padding: 12px 16px;
    font-size: 12px;
    color: var(--amber-text);
    background: var(--amber-soft);
    border-radius: var(--radius);
}

/* --------------------------------------------------------------------------
   27. Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 1023px) {
    .mobile-bar {
        display: flex;
    }

    /* The sidebar is not removed here, it is parked off-screen: the hamburger
       slides the real navigation in, so every page stays reachable instead of
       the handful a bottom bar had room for. */
    .sidebar-container {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        z-index: 66;
        transform: translateX(-100%);
    }

    .sidebar-container.open {
        transform: translateX(0);
    }

    .mobile-scrim.open {
        display: block;
    }

    .sidebar {
        height: 100vh;
        border-radius: 0;
    }

    /* Collapsing makes no sense on a drawer that is already hidden by default. */
    .sidebar-toggle {
        display: none;
    }

    /* Room for the fixed mobile bar, then the same 16px everywhere else. */
    main {
        padding: 58px var(--pad) var(--pad);
    }

    .chat-layout,
    .notes-layout,
    .detail-layout {
        grid-template-columns: 1fr;
    }

    main > header {
        flex-direction: column;
        align-items: stretch;
        gap: 16px;
    }

    main > header h1 {
        font-size: 27px;
    }
}

/* --------------------------------------------------------------------------
   28. Side panel (project view / edit / add)
   -------------------------------------------------------------------------- */

/* One panel does view, edit and create. It slides over the right edge rather
   than pushing the board, so the column a card came from stays put. */
.side-panel {
    position: fixed;
    top: 16px;
    right: 16px;
    bottom: 16px;
    z-index: 60;
    width: 480px;
    max-width: calc(100vw - 32px);
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
    box-shadow: 0 24px 48px rgba(15, 23, 42, 0.18);
}

.side-panel[aria-hidden="true"] {
    display: none;
}

.side-panel-head {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px 0 24px;
}

/* Says "Saved" or names the field that failed. Empty the rest of the time, so
   it must not reserve space when it has nothing to say. */
.side-panel-status {
    flex: 1;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.side-panel-status.error {
    color: var(--rose-text);
}

.side-panel-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 8px 24px 24px;
}

.side-panel-foot {
    flex-shrink: 0;
    padding: 16px 24px;
    border-top: 1px solid var(--border-solid);
}

.side-panel h2 {
    padding: 24px 0 8px;
}

.field-row + .field-row {
    margin-top: 14px;
}

/* A field with a button riding beside it: the box stretches, the button keeps
   its size. Used by the Drive folder, where the address is editable and the
   button is the thing you actually want. */
/* A rendered README.
 *
 * Everything inside comes from somebody else's repository, so the rules are
 * written against the article rather than against classes the content will
 * never carry. Sizes are held close to the page's own so a document with six
 * heading levels does not shout, and anything that could be wider than the
 * column — a table, a code block, a long URL — is made to fit rather than
 * pushing the layout sideways.
 */
.readme {
    line-height: 1.6;
}

.readme > :first-child {
    margin-top: 0;
}

.readme h1,
.readme h2,
.readme h3,
.readme h4,
.readme h5,
.readme h6 {
    margin: 28px 0 10px;
    line-height: 1.3;
    color: var(--text-strong);
}

.readme h1 { font-size: 22px; }
.readme h2 { font-size: 18px; }
.readme h3 { font-size: 16px; }
.readme h4,
.readme h5,
.readme h6 { font-size: 14px; }

.readme h1,
.readme h2 {
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border-solid);
}

.readme p,
.readme ul,
.readme ol,
.readme blockquote,
.readme table,
.readme pre {
    margin: 0 0 14px;
}

.readme ul,
.readme ol {
    padding-left: 22px;
}

.readme li {
    margin: 4px 0;
}

.readme blockquote {
    padding: 2px 0 2px 14px;
    border-left: 3px solid var(--border-strong);
    color: var(--text-secondary);
}

.readme code {
    padding: 2px 5px;
    font-size: 13px;
    background: var(--surface-muted);
    border: 1px solid var(--border-solid);
    border-radius: 4px;
}

.readme pre {
    padding: 12px 14px;
    overflow-x: auto;
    background: var(--surface-muted);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
}

/* A block already has the frame, so the code inside it does not need a second
   one, nor its own scroll. */
.readme pre code {
    padding: 0;
    background: none;
    border: 0;
}

/* Tables in a README are written for a browser window, not for this column.
   The wrapper scrolls instead of the page. */
.readme table {
    display: block;
    width: fit-content;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
}

.readme th,
.readme td {
    padding: 6px 10px;
    text-align: left;
    border: 1px solid var(--border-solid);
}

.readme th {
    background: var(--surface-muted);
}

.readme img {
    max-width: 100%;
    height: auto;
}

/* A bare URL in a paragraph would otherwise widen the whole page. */
.readme a {
    word-break: break-word;
}

.readme hr {
    margin: 22px 0;
    border: 0;
    border-top: 1px solid var(--border-solid);
}

/* Task lists: the marker is the checkbox, so the bullet would be a second one. */
.readme li input[type="checkbox"] {
    margin-right: 6px;
}

/* The enrolment QR: the library hands back a PNG, which is small, so it is
   scaled up and kept crisp rather than smoothed into mush. */
.totp-qr {
    text-align: center;
}

.totp-qr img {
    width: 200px;
    height: 200px;
    image-rendering: pixelated;
    background: #fff;
    padding: 8px;
    border-radius: 8px;
}

.field-with-action {
    display: flex;
    align-items: center;
    gap: 8px;
}

.field-with-action .field {
    flex: 1;
    min-width: 0;
}

.field-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
}

.field-grid .field-row + .field-row {
    margin-top: 0;
}

/* The point of the panel: a field reads as text until you interact with it.
   No box, no fill — the border only appears on hover and focus. */
.field {
    width: 100%;
    height: var(--control-h);
    padding: 0 10px;
    font-family: inherit;
    font-size: 14px;
    color: var(--text);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius);
    box-shadow: none;
}

.field:hover {
    border-color: var(--border-solid);
}

.field:focus {
    background: var(--surface);
    border-color: var(--border-strong);
    outline: none;
}

.field::placeholder {
    color: var(--text-muted);
}

.field-title {
    padding-left: 10px;
    font-size: 22px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--text-dark);
}

/* A field that just saved flashes its border; a rejected one keeps a red edge
   until the next attempt, so the failure is attached to the field that failed
   rather than to a message somewhere else. */
.field.saved {
    border-color: var(--green);
}

.field.failed {
    border-color: var(--rose);
}

.deliverable-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.deliverable {
    display: grid;
    grid-template-columns: 118px 1fr 56px 140px 32px;
    align-items: center;
    gap: 6px;
    padding: 4px 0;
}

.deliverable + .deliverable {
    border-top: 1px solid var(--border-solid);
}

.deliverable .field {
    padding: 6px 8px;
    font-size: 13px;
}

.deliverable-hours {
    text-align: right;
}

/* --------------------------------------------------------------------------
   29. Team administration
   -------------------------------------------------------------------------- */

/* Organizations and the groups inside them. Nesting is shown by indenting the
   row, so the depth of a hierarchy reads at a glance. */
.org {
    padding: 12px 0;
}

.org + .org {
    border-top: 1px solid var(--border-solid);
}

.tree-row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 7px 10px;
    text-align: left;
    border-radius: var(--radius);
}

.tree-row:hover {
    background: rgba(255, 255, 255, 0.6);
}

.tree-row svg {
    color: var(--text-muted);
    flex-shrink: 0;
}

.tree-name {
    font-weight: 600;
    color: var(--text-strong);
}

.tree-note {
    font-size: 12px;
    color: var(--text-secondary);
}

/* Each level of nesting steps in by one notch. */
.tree-child {
    margin-left: 22px;
    border-left: 1px solid var(--border-solid);
    padding-left: 6px;
}

.check-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.check-list li {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 2px;
    font-size: 13px;
}

.check-list li + li {
    border-top: 1px solid var(--border-solid);
}

.check-list input[type="checkbox"] {
    width: auto;
    margin: 0;
    flex-shrink: 0;
}

.check-note {
    margin-left: auto;
    font-size: 11px;
    color: var(--text-muted);
}

/* A note in smaller type next to what it explains. */
small {
    display: block;
    margin: 0 0 10px;
    font-size: 12px;
    color: var(--text-secondary);
}

/* A task card is mostly its title, which is a sentence rather than a name and
   has to wrap. */
.task-title {
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-strong);
}

/* Tasks grouped by project inside a state column. Each group folds on its own,
   so a board spanning several projects can be narrowed to the one in hand. */
.task-group + .task-group {
    margin-top: 14px;
}

.task-group-head {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 4px 2px 8px;
    text-align: left;
    font-size: 12px;
    color: var(--text-secondary);
}

.task-group-head svg {
    color: var(--text-muted);
    flex-shrink: 0;
}

.task-group-cards {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.task-group.collapsed .task-group-cards {
    display: none;
}

.task-group.collapsed .task-group-chevron {
    transform: rotate(-90deg);
}

/* The project filter on the task board: a select rather than a row of links,
   which stops being usable past a handful of projects. */
.filter-form {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

.filter-form .field {
    width: auto;
    min-width: 190px;
    border-color: var(--border-solid);
}

/* A task card. The title is the card; everything else is a footnote, and only
   appears when it distinguishes this task from its neighbours. */
.task-card {
    gap: 6px;
}

/* Clamped to four lines. The titles came from TODO.md, where a line runs to
   175 characters, and a column is 200px wide: without this a single task fills
   the screen. The full text is on the card's title attribute. */
.task-title {
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.task-card .board-card-foot {
    font-size: 11px;
}

.task-priority {
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* Priority reads as a stripe down the edge rather than a badge, so it is
   visible while scanning without taking a line of its own. Normal draws
   nothing: most tasks are normal, and a mark on everything marks nothing. */
.priority-high {
    border-left: 3px solid var(--rose);
}

.priority-high .task-priority {
    color: var(--rose-text);
}

.priority-low {
    border-left: 3px solid var(--border-strong);
}

.priority-low .task-priority {
    color: var(--text-muted);
}

.board-more {
    margin: 0;
    padding: 8px 2px;
    font-size: 11px;
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   30. Task table
   -------------------------------------------------------------------------- */

/* `fixed` is what makes the widths below mean anything: with `auto` the browser
   sizes columns from their content and ignores what is asked for. */
/* Everything not given a width shares what is left, so the table fills the row
   however wide the window is. The title takes the slack because it is the one
   column whose content has no natural end. */
.task-table .col-check       { width: 36px; }
.task-table .col-state       { width: 130px; }
.task-table .col-priority    { width: 90px; }
.task-table .col-assignee    { width: 120px; }
.task-table .col-deliverable { width: 140px; }
.task-table .col-project     { width: 130px; }
.task-table .col-origin      { width: 170px; }
/* No width: it takes whatever the others leave, however narrow that is. */
.task-table .col-title       { width: auto; min-width: 0; }

/* Tighter than the default table padding: a list meant for scanning fits more
   rows on screen, and the rows are single-line anyway. */
/* The task table is the one whose cells must stay on a single line: its titles
   are sentences, and a wrapped one would make every row a different height. */
.task-table td {
    white-space: nowrap;
}

.task-table .col-check input {
    width: auto;
    margin: 0;
}

.sort-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: inherit;
}

.sort-link:hover {
    color: var(--text-strong);
}

.sort-link.active {
    color: var(--text-dark);
}

.sort-arrow {
    font-size: 10px;
}

/* Sits above the table while a selection is live. */
.bulk-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    padding: 10px 14px;
    background: var(--surface);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
    box-shadow: var(--shadow-soft);
}

.bulk-count {
    font-size: 12px;
    font-weight: 700;
    color: var(--text-strong);
}

.bulk-bar .field {
    width: auto;
    min-width: 170px;
    border-color: var(--border-solid);
}

/* The task title is edited in a textarea rather than an input: the imported
   ones run past a single line, and a field that scrolls sideways cannot be
   read while typing. */
.side-panel textarea.field-title {
    resize: vertical;
    line-height: 1.35;
}

/* A row in the task table is a button in all but name. */
.task-table tbody tr[data-action="open-task"] {
    cursor: pointer;
}

/* A textarea is many lines by definition, so the single-control height does
   not apply: it takes vertical padding back and grows with its content. */
textarea,
textarea.field {
    height: auto;
    min-height: calc(var(--control-h) * 2);
    padding: 8px var(--pad);
    line-height: 1.45;
}

/* --------------------------------------------------------------------------
   Reporting a problem
   -------------------------------------------------------------------------- */

/* Reachable from every page, so it floats above them rather than taking a
   place in any one layout. Bottom right, clear of the sidebar. */
.fab {
    position: fixed;
    right: var(--pad);
    bottom: var(--pad);
    z-index: 60;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    color: var(--surface);
    background: var(--brand);
    border: 0;
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-float);
    cursor: pointer;
}

.fab:hover {
    background: var(--text-dark);
}

/* The report form. `<dialog>` brings the modal behaviour with it — the
   backdrop, Escape to close, focus kept inside — so none of that is written
   again here. */
dialog {
    width: min(560px, calc(100vw - 2 * var(--pad)));
    padding: 0;
    color: var(--text);
    background: var(--surface);
    border: 0;
    border-radius: var(--radius);
    box-shadow: var(--shadow-float);
}

dialog::backdrop {
    background: rgba(19, 28, 47, 0.4);
}

dialog form {
    display: flex;
    flex-direction: column;
    gap: var(--pad);
    padding: var(--pad);
}

dialog header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pad);
}

dialog h2 {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-strong);
}

dialog textarea {
    /* The one control here that is deliberately not 32px: it holds a
       paragraph, so it is sized by its rows. */
    height: auto;
    resize: vertical;
}

dialog footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
}

/* The status message takes the room left over, so the buttons stay put
   whether or not there is anything to say. */
dialog footer .side-panel-status {
    margin-right: auto;
}

/* A report is typed prose: keep the reporter's line breaks, and let a long
   line wrap rather than widen the page. */
.report-body {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* A row that opens something says so under the pointer. */
main table tr[data-action="open-row"] {
    cursor: pointer;
}

/* --------------------------------------------------------------------------
   Dragging cards on the board
   -------------------------------------------------------------------------- */

/* A card that can be moved says so under the pointer, and shows it is being
   carried by fading rather than by leaving its place: the gap it opens as it
   travels is the real feedback. */
.board-card[draggable] {
    cursor: grab;
}

.board-card.dragging {
    opacity: 0.4;
    cursor: grabbing;
}

/* The column the card would land in. Inset, so it reads as the space filling
   rather than as a border appearing. */
.board-column-cards.over {
    background: var(--panel-alt);
    border-radius: var(--radius);
    box-shadow: inset 0 0 0 1px var(--border-strong);
}



/* Recording a spoken report. The button, the state and the playback sit on one
   line until the clip arrives, which pushes the player onto its own. */
.recorder {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.recorder audio {
    width: 100%;
    height: var(--control-h);
}

/* While recording, the button is the thing on screen that is happening. */
.recorder button:has(use[href$="#i-stop"]) {
    color: var(--rose-text);
    border-color: var(--rose);
}

/* --------------------------------------------------------------------------
   Code, for the pages that have to show a command
   -------------------------------------------------------------------------- */

/* A command somebody will copy. It scrolls rather than wraps, because a
   wrapped shell command is a command that gets pasted wrong. */
pre {
    overflow-x: auto;
    padding: var(--pad);
    background: var(--surface-muted);
    border: 1px solid var(--border-solid);
    border-radius: var(--radius);
}

code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    color: var(--text-strong);
}

/* Inline in a sentence, where it needs to be picked out rather than boxed. */
:not(pre) > code {
    padding: 1px 5px;
    background: var(--surface-muted);
    border-radius: 5px;
}

main p + pre,
main pre + p {
    margin-top: 12px;
}

/* A short list of facts about one thing: label on the left, value on the
   right. Used where a record is read rather than edited. */
.facts {
    list-style: none;
    margin-bottom: var(--pad);
}

.facts li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pad);
    height: var(--control-h);
    font-size: 14px;
    color: var(--text-secondary);
}

.facts li + li {
    border-top: 1px solid var(--border-solid);
}

/* The dialog's own footer follows the report one: status to the left, the
   buttons to the right. */
dialog pre {
    /* A token is one long unbroken string; let it wrap rather than push the
       dialog wider than the screen. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* A dialog that carries a page of instructions rather than a single question
   has to scroll, and stop short of the top and bottom of the screen. */
dialog {
    max-height: calc(100vh - 2 * var(--pad));
    overflow-y: auto;
}

/* Inside one, a heading separates sections rather than titling the whole
   thing, so it needs the space a page heading gets for free. */
dialog h2 + p,
dialog p + h2,
dialog pre + h2,
dialog ul + h2 {
    margin-top: 12px;
}

/* Numbered steps somebody follows elsewhere — in another application's
   settings, say. The number carries the order, so the text does not have to
   say "then". */
.steps {
    /* The reset strips every list's padding, which is where a number sits, so
       it has to come back or the digits fall outside the dialog. */
    padding-left: 20px;
    list-style: decimal;
    font-size: 13px;
    color: var(--text-secondary);
}

.steps li {
    padding-left: 4px;
}

.steps li + li {
    margin-top: 8px;
}

/* Money that is late. The one figure on the panel worth colouring: the others
   are facts, this one is a thing to do something about. */
.text-rose {
    color: var(--rose);
}

/* A badge that is also a button — the instalment status, which is how a
   payment gets recorded as arrived. */
button.badge {
    cursor: pointer;
    border: 0;
}
