/* Miftahun Theme — design tokens applied via attributes on <html>.
 *
 * The JS applier sets: data-mt-color (t1..t5|custom), data-mt-font
 * (system|plex|public|nunito), data-mt-density (balanced|compact|relaxed).
 * "custom" colors arrive as inline CSS variables set by the applier.
 *
 * Deliberately narrow: we override Frappe's own CSS variables where they
 * exist and touch a minimal set of component selectors. Status colors
 * (success/warning/danger) are NOT remapped — red stays clinical.
 */

/* ---------- fonts (latin subset; extend with more subsets if needed) ------ */
@font-face { font-family: 'IBM Plex Sans'; font-weight: 400; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/IBMPlexSans-400.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Sans'; font-weight: 600; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/IBMPlexSans-600.woff2') format('woff2'); }
/* The two faces the Estate skin asks for. Added 15 Aug 2026 after measuring that
 * it requested them and the theme shipped neither: `--mt-disp` fell through to
 * Arial Narrow and then to system-ui, so the KPI figures were never condensed,
 * and `--mt-mono` fell through to the platform monospace. A font stack that
 * silently degrades looks like a design choice, which is why it went unnoticed.
 * IBM Plex is OFL-1.1, latin subset only, ~50 KB for all three. */
@font-face { font-family: 'IBM Plex Sans Condensed'; font-weight: 600; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/IBMPlexSansCondensed-600.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 400; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/IBMPlexMono-400.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 600; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/IBMPlexMono-600.woff2') format('woff2'); }
/* Source Serif 4, added for the Mall style conversion (branch mall-style-conversion).
 * Self-hosted like every other face here: the theme's rule is no third-party
 * request on page load, and a converted palette is no reason to break it.
 * OFL-1.1, latin subset, ~14 KB for both weights. */
@font-face { font-family: 'Source Serif 4'; font-weight: 400; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/SourceSerif4-400.woff2') format('woff2'); }
@font-face { font-family: 'Source Serif 4'; font-weight: 600; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/SourceSerif4-600.woff2') format('woff2'); }
@font-face { font-family: 'Public Sans'; font-weight: 400; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/PublicSans-400.woff2') format('woff2'); }
@font-face { font-family: 'Public Sans'; font-weight: 600; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/PublicSans-600.woff2') format('woff2'); }
@font-face { font-family: 'Nunito Sans'; font-weight: 400; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/NunitoSans-400.woff2') format('woff2'); }
@font-face { font-family: 'Nunito Sans'; font-weight: 600; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/NunitoSans-600.woff2') format('woff2'); }
@font-face { font-family: 'Roboto'; font-weight: 400; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/Roboto-400.woff2') format('woff2'); }
/* Roboto ships 500, not 600 — declaring it as 600 keeps our weight scale consistent. */
@font-face { font-family: 'Roboto'; font-weight: 600; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/Roboto-500.woff2') format('woff2'); }
/* Manrope, for the Expressive surface's figures. One variable file covers the
 * whole weight axis, which is why a single @font-face declares 200-800. */
@font-face { font-family: 'Manrope'; font-weight: 200 800; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/Manrope-800.woff2') format('woff2'); }
/* Inter, the face of the Option 1 drawing. Variable; one file, 400-700. */
@font-face { font-family: 'Inter'; font-weight: 400 700; font-display: swap;
  src: url('/assets/miftahun_theme/fonts/Inter-var.woff2') format('woff2'); }

/* ---------- layout -------------------------------------------------------- */
/* Frappe caps page content at --page-max-width (900px, set in its own
 * common/css_variables.scss). On a 1920px monitor that leaves roughly half the
 * screen unused — but the cap is not arbitrary: it keeps form labels and inputs
 * near a readable line length.
 *
 * This adapts instead of picking one number. Note that max-width is already
 * responsive downward — it never forces an element wider than its container, so
 * on a laptop or tablet the ceiling simply does not bind and content shrinks on
 * its own. What a fixed value cannot do is hold back on a very large monitor,
 * which is what the upper bound below is for.
 *
 *   floor 900px  — never constrain tighter than Frappe's own default
 *   92vw         — track the viewport through the middle range
 *   ceiling 1800px — past this, form rows get too long to scan comfortably
 *
 * Pure CSS: no viewport detection, no JS, no resize listener. It re-evaluates
 * as the window changes, including on an external monitor being plugged in.
 *
 * Same specificity as Frappe's :root, so this wins on source order alone —
 * frappe's desk.bundle.css is itself an app_include_css entry and frappe is
 * always the first app, so our stylesheet is appended after it. No !important.
 */
:root { --page-max-width: clamp(900px, 92vw, 1800px); }

/* ---------- responsive type and chrome scale ------------------------------ */
/* Frappe defines its whole type scale in px (--text-base: 14px, and so on).
 * px does not respond to the reader's own browser font-size setting — the
 * standard accommodation for low vision. Verified in the browser on
 * education.miftahun.com: with the root raised 16px -> 20px, a px token stayed
 * at 14px while the rem equivalent moved to 17.5px.
 *
 * These are the identical sizes at the default 16px root, so nothing shifts for
 * anyone who has not changed their setting — but they now follow the reader.
 *
 * Deliberately NOT converted: border widths stay 1px, because hairlines should
 * not thicken with text and sub-pixel borders render badly; and font size does
 * not scale with viewport, because in a data-dense desk a larger screen should
 * show more rows, not bigger text. Density is the lever for that.
 */
:root {
  --text-tiny: 0.6875rem;   /* 11px */
  --text-2xs:  0.75rem;     /* 12px */
  --text-xs:   0.75rem;     /* 12px */
  --text-sm:   0.8125rem;   /* 13px */
  --text-md:   0.875rem;    /* 14px */
  --text-base: 0.875rem;    /* 14px */
  --text-lg:   1rem;        /* 16px */
  --text-xl:   1.125rem;    /* 18px */
  --text-2xl:  1.25rem;     /* 20px */
  --text-3xl:  1.5rem;      /* 24px */
  --text-4xl:  1.625rem;    /* 26px */

  /* Chrome sized in rem too, or enlarged text clips inside fixed-height bars. */
  --navbar-height:    3rem;    /* 48px */
  --page-head-height: 3rem;    /* 48px */
  --sidebar-width:    13.75rem; /* 220px */
}

/* WCAG 2.2 SC 2.4.11 Focus Not Obscured (Minimum, AA): when a keyboard user
 * tabs to a control that sits just above the fold, the browser scrolls it into
 * view — directly underneath the navbar and page head, both of which are
 * position: sticky. The focused control ends up hidden behind them.
 *
 * Frappe sets scroll-margin-top on two individual elements but has no global
 * guard, and there are six-plus sticky elements in the desk. scroll-padding on
 * the scroll container is the blanket fix: it reserves space at the top of
 * every programmatic scroll, so focus always lands below the sticky chrome.
 * Costs nothing when nothing is sticky. */
html {
  scroll-padding-top: calc(var(--navbar-height, 48px) + var(--page-head-height, 48px) + 0.5rem);
}

/* ---------- color presets ------------------------------------------------- */
html[data-mt-color="t1"] { --mt-primary:#0F766E; --mt-accent:#2DD4BF; --mt-ink:#ffffff; --mt-accent-ink:#04211D; }
html[data-mt-color="t2"] { --mt-primary:#1D4ED8; --mt-accent:#60A5FA; --mt-ink:#ffffff; --mt-accent-ink:#0A1B33; }
html[data-mt-color="t3"] { --mt-primary:#047857; --mt-accent:#34D399; --mt-ink:#ffffff; --mt-accent-ink:#03291C; }
html[data-mt-color="t4"] { --mt-primary:#4F46E5; --mt-accent:#818CF8; --mt-ink:#ffffff; --mt-accent-ink:#111436; }
html[data-mt-color="t5"] { --mt-primary:#1E3A5F; --mt-accent:#93B8E0; --mt-ink:#ffffff; --mt-accent-ink:#0B1B2E; }
html[data-mt-color="t6"] { --mt-primary:#714B67; --mt-accent:#D4A9C7; --mt-ink:#ffffff; --mt-accent-ink:#331A2E; }
/* data-mt-color="custom": --mt-primary/--mt-accent set inline by the applier */

/* Map onto Frappe's variable names, light mode. */
html[data-mt-color] {
  --primary: var(--mt-primary);
  --primary-color: var(--mt-primary);
  --btn-primary: var(--mt-primary);
  --sidebar-select-color: color-mix(in srgb, var(--mt-primary) 12%, transparent);
  --checkbox-color: var(--mt-primary);
}
html[data-mt-color] .btn-primary {
  background-color: var(--mt-primary);
  border-color: var(--mt-primary);
  color: var(--mt-ink);
}
html[data-mt-color] .btn-primary:hover,
html[data-mt-color] .btn-primary:active {
  background-color: color-mix(in srgb, var(--mt-primary) 88%, black);
  border-color: color-mix(in srgb, var(--mt-primary) 88%, black);
}
html[data-mt-color] a:not(.btn):not(.no-underline) { color: var(--mt-primary); }
html[data-mt-color] .desk-sidebar-item.selected,
html[data-mt-color] .sidebar-item-container .selected {
  background-color: color-mix(in srgb, var(--mt-primary) 10%, transparent);
  color: var(--mt-primary);
}
html[data-mt-color] input:focus, html[data-mt-color] select:focus,
html[data-mt-color] textarea:focus, html[data-mt-color] .form-control:focus {
  border-color: var(--mt-primary);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--mt-primary) 25%, transparent);
}

/* Dark mode: flip to the light accent so contrast holds on dark surfaces. */
html[data-theme="dark"][data-mt-color] {
  --primary: var(--mt-accent);
  --primary-color: var(--mt-accent);
  --btn-primary: var(--mt-accent);
  --checkbox-color: var(--mt-accent);
}
html[data-theme="dark"][data-mt-color] .btn-primary {
  background-color: var(--mt-accent);
  border-color: var(--mt-accent);
  color: var(--mt-accent-ink);
}
html[data-theme="dark"][data-mt-color] a:not(.btn):not(.no-underline) { color: var(--mt-accent); }
html[data-theme="dark"][data-mt-color] .desk-sidebar-item.selected,
html[data-theme="dark"][data-mt-color] .sidebar-item-container .selected {
  background-color: color-mix(in srgb, var(--mt-accent) 14%, transparent);
  color: var(--mt-accent);
}

/* ---------- typefaces ----------------------------------------------------- */
html[data-mt-font="plex"]   { --mt-font: 'IBM Plex Sans'; }
html[data-mt-font="public"] { --mt-font: 'Public Sans'; }
html[data-mt-font="nunito"] { --mt-font: 'Nunito Sans'; }
html[data-mt-font="roboto"] { --mt-font: 'Roboto'; }
html[data-mt-font="inter"]  { --mt-font: 'Inter'; }
html[data-mt-font="plex"] body, html[data-mt-font="public"] body,
html[data-mt-font="nunito"] body, html[data-mt-font="roboto"] body,
html[data-mt-font="inter"] body {
  --font-stack: var(--mt-font), -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-family: var(--font-stack);
}
/* data-mt-font="system" (or absent): stock stack, nothing to do. */

/* ---------- density ------------------------------------------------------- */
html[data-mt-density="compact"] {
  --border-radius: 2px; --border-radius-sm: 2px; --border-radius-md: 3px;
  --border-radius-lg: 4px; --padding-xs: 2px; --padding-sm: 4px;
}
/* rem, not px, and min-height, not height: Frappe lets list rows size to their
 * content. Pinning them to a pixel value clips the text when a user enlarges
 * their browser font or zooms to 200% — which WCAG 1.4.4 requires us to
 * survive. 2rem is 32px at the default root size, and grows with the user. */
html[data-mt-density="compact"] .list-row, html[data-mt-density="compact"] .list-row-head {
  min-height: 2rem; padding-top: 0; padding-bottom: 0;
}
/* WCAG 2.2 SC 2.5.8 Target Size (Minimum, AA) requires 24x24 CSS px. With
 * Frappe's .btn at font-size 14px / line-height 1.15, our 3px padding gives
 * 22.1px of content box — it only clears 24px because .btn happens to carry a
 * 1px border. That is accidental compliance: any borderless variant fails.
 * State the floor instead of inheriting it by luck. */
html[data-mt-density="compact"] .btn {
  padding-top: 3px; padding-bottom: 3px;
  min-height: 1.5rem;
}

html[data-mt-density="relaxed"] {
  --border-radius: 10px; --border-radius-sm: 8px; --border-radius-md: 12px;
  --border-radius-lg: 14px;
}
html[data-mt-density="relaxed"] .list-row, html[data-mt-density="relaxed"] .list-row-head {
  min-height: 3rem;
}
html[data-mt-density="relaxed"] .btn { padding-top: 7px; padding-bottom: 7px; }
/* "balanced": stock metrics, nothing to override. */

/* ---------- header theme-picker button ------------------------------------ */
.mt-theme-btn {
  background: none;
  border: none;
  display: flex;
  align-items: center;
  padding: 6px 8px;
  cursor: pointer;
  color: var(--text-muted, #6B7280);
  border-radius: 6px;
}
.mt-theme-btn:hover { color: var(--mt-primary, var(--text-color, #1F2430)); }
.mt-theme-btn:focus-visible {
  outline: 2px solid var(--mt-primary, #0F766E);
  outline-offset: 1px;
}

/* ---------- surface: Flat (Odoo style) ------------------------------------ */
/* Light-gray page ground, white flat cards, shadows almost gone. Works with
 * any color preset; pairs naturally with Plum + Roboto + Relaxed. */
html[data-mt-surface="flat"] {
  --bg-color: #F1F2F5;
  --card-bg: #FFFFFF;
  --fg-color: #FFFFFF;
  --subtle-fg: #F7F8F9;
  --shadow-sm: 0 1px 2px rgba(25, 28, 33, 0.05);
  --shadow-base: 0 1px 3px rgba(25, 28, 33, 0.07);
}
html[data-mt-surface="flat"] .widget,
html[data-mt-surface="flat"] .frappe-card,
html[data-mt-surface="flat"] .form-page {
  background: var(--card-bg);
  box-shadow: var(--shadow-sm);
  border: 1px solid #E7E9EC;
}
html[data-mt-surface="flat"] .btn { box-shadow: none; }
html[data-mt-surface="flat"] .navbar {
  background: #FFFFFF;
  border-bottom: 1px solid #E7E9EC;
}
/* Dark mode: keep depth relationships, just flatter. */
html[data-theme="dark"][data-mt-surface="flat"] {
  --bg-color: #121417;
  --card-bg: #1B1E23;
  --fg-color: #1B1E23;
  --shadow-sm: none;
  --shadow-base: none;
}
html[data-theme="dark"][data-mt-surface="flat"] .widget,
html[data-theme="dark"][data-mt-surface="flat"] .frappe-card,
html[data-theme="dark"][data-mt-surface="flat"] .form-page {
  background: var(--card-bg);
  border: 1px solid #2A2E35;
  box-shadow: none;
}
html[data-theme="dark"][data-mt-surface="flat"] .navbar {
  background: #16181C;
  border-bottom: 1px solid #2A2E35;
}

/* ---------- forced colours (Windows High Contrast) ------------------------ */
/* In forced-colors mode the OS replaces the palette. Frappe does not handle
 * this, and our tinted selection backgrounds are the thing that breaks: a
 * colour-mix() fill at 10–16% opacity is dropped, leaving the selected item
 * visually identical to the rest of the sidebar. Hand those states back to the
 * system palette so "which item am I on" survives. Nobody on this theme should
 * lose their place because they use high contrast. */
@media (forced-colors: active) {
  html[data-mt-color] .desk-sidebar-item.selected,
  html[data-mt-color] .sidebar-item-container .selected,
  html[data-theme="dark"][data-mt-color] .desk-sidebar-item.selected,
  html[data-theme="dark"][data-mt-color] .sidebar-item-container .selected {
    background-color: Highlight;
    color: HighlightText;
    forced-color-adjust: none;
  }
  /* Our focus ring is a preset colour, which forced-colors discards. */
  .mt-theme-btn:focus-visible,
  html[data-mt-color] input:focus, html[data-mt-color] select:focus,
  html[data-mt-color] textarea:focus, html[data-mt-color] .form-control:focus {
    outline: 2px solid Highlight;
    outline-offset: 1px;
    box-shadow: none;
  }
}

/* ---------- Espresso semantic tokens (v16) -------------------------------- */
/* The rules above target the v15 vocabulary (--bg-color, --card-bg, --fg-color).
 * v16's newer chrome — the persistent sidebar, modals, card surfaces, muted
 * text — reads Espresso's semantic names instead, which the block above never
 * touches. Measured in the compiled desk.bundle.css shipping on healthcare:
 * 240 references to the legacy names, 78 to these. Without this block the Flat
 * surface stops at roughly three quarters of the desk.
 *
 * Token declarations only — no selectors against Frappe's markup — so this
 * degrades to "no effect" rather than breaking if the names change upstream.
 */
html[data-mt-surface="flat"] {
  --surface-cards:    #FFFFFF;
  --surface-modal:    #FFFFFF;
  --surface-menu-bar: #F7F8F9;
  --surface-selected: color-mix(in srgb, var(--mt-primary) 12%, transparent);
  --outline-gray-1:   #E7E9EC;
  --outline-gray-2:   #DDE0E4;
}
html[data-theme="dark"][data-mt-surface="flat"] {
  --surface-cards:    #1B1E23;
  --surface-modal:    #23262B;
  --surface-menu-bar: #16181C;
  --surface-selected: color-mix(in srgb, var(--mt-accent) 16%, transparent);
  --outline-gray-1:   #2A2E35;
  --outline-gray-2:   #343941;
}

/* ---------- target size (WCAG 2.2 SC 2.5.8, AA) --------------------------- */
/* Measured in Chrome at 1440x675 on education.miftahun.com/app/student and
 * healthcare.miftahun.com/app/patient/new, by probing each interactive
 * element's *effective* hit area with document.elementFromPoint rather than
 * reading getBoundingClientRect().
 *
 * That distinction is the whole of this section. A naive box audit counts 29 of
 * 77 targets under 24px on the Student list; probing the hit area gives 16. The
 * 13 that vanish are the row and header checkboxes, which look like the worst
 * offenders on paper — a 14x14 painted box — but which Frappe already backs
 * with input.list-row-checkbox::after { left/top/right/bottom: -8px }, i.e. a
 * 28x28 hit area. They pass already. An earlier draft of this block "fixed"
 * them by re-declaring left/top/width/height on that same pseudo-element and
 * measurably made things worse: the header checkbox ended up with a displaced
 * 24x24 overlay and stopped responding 11px from its own centre. They are left
 * alone deliberately — see the closing note.
 *
 * Not scoped to html[data-mt-*]. A hit area is not a taste setting, and this
 * follows the same reasoning as the SC 2.4.11 scroll-padding rule further up:
 * an accessibility floor applies to every preset or it is not a floor.
 *
 * These are selectors against Frappe's markup rather than token overrides,
 * which the rest of this file avoids. It is unavoidable here — CSS cannot
 * select "elements whose box is under 24px", so every offender has to be named,
 * and each rule is therefore checked against the upstream declarations it sits
 * next to rather than assumed safe.
 */

/* The row subject link — the primary action in every list, and the one target
 * here that a user hits hundreds of times a day. 14px text in a 21px line box,
 * 3px short. There is room: the row is 41px and .list-subject is a fixed 30px,
 * so 9px either side goes unused.
 *
 * Growing the line box grows the hit area symmetrically, which is why this is
 * line-height and not padding or min-height: measured top 142.5 -> 141.0 and
 * height 21 -> 24, so the glyphs stay exactly where they were rather than
 * shifting 1.5px up as a min-height would have moved them.
 *
 * max(), not a flat 24px, because this file converts Frappe's px type scale to
 * rem so it follows the reader's browser font size. A reader at a 20px root
 * gets 17.5px text, where a flat 24px line box would be a 1.37 ratio — tighter
 * than the 1.5 Frappe ships, crowding descenders on the one control we are
 * trying to make easier to hit. 1.5em reproduces Frappe's own ratio once it
 * exceeds the floor; at default settings max() resolves to exactly 24px, so
 * nothing moves for anyone who has not changed their setting.
 *
 * Verified: all 12 row heights stayed 41px, .list-subject stayed 30px, .result
 * stayed 526px, document height unchanged, no horizontal overflow. Row pitch is
 * 41px (32px at compact density), both comfortably over 24, so enlarging the
 * hit area cannot make neighbouring rows' targets touch. */
.list-row-col.list-subject a.ellipsis {
  line-height: max(24px, 1.5em);
}

/* Icon-only buttons that are genuinely their own target: the workspace/app
 * switcher chevron in the sidebar header (16x16) and the desktop notification
 * bell (20x21.7). Both are .btn-reset — deliberately stripped of padding — and
 * both sit alone, with nothing else interactive within 40px, so the shortfall
 * is a real one rather than an artefact of a clickable ancestor overlapping
 * them.
 *
 * A centred transparent pseudo-element takes the hit area to 24x24 without
 * moving the icon, the sidebar header, or the bar around it: it is out of flow,
 * so it cannot push anything. .drop-icon ships overflow:hidden, which would
 * clip the overlay, so it is reopened here.
 *
 * Checked before writing this: neither element has a ::before or ::after
 * upstream (computed content is 'none' on both), so unlike the list checkboxes
 * nothing is being overwritten. Verified by hit-testing afterwards — both
 * capture the pointer at +/-11px from centre and release it at +/-14px, which
 * is a 24x24 area and not a hair more.
 *
 * 24px literal, not rem: SC 2.5.8 states an absolute CSS px floor, and these
 * icons are fixed-size SVGs that do not scale with the reader's font. Same
 * reasoning as the border widths left in px at the top of this file. */
.sidebar-header .btn-reset.drop-icon,
.btn-reset.desktop-notification-icon {
  position: relative;
  overflow: visible;
}
.sidebar-header .btn-reset.drop-icon::after,
.btn-reset.desktop-notification-icon::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 24px;
  height: 24px;
  transform: translate(-50%, -50%);
}

/* Form checkboxes. Unlike the list ones these get no overlay from Frappe, but
 * they are wrapped in a <label>, and a label toggles its control natively — so
 * the target is the label, not the 14x14 box. Measured 105.9x22.5 on the
 * Patient form's "Invite as User": width is fine, height misses by 1.5px.
 *
 * min-height alone, leaving Frappe's align-items:start and padding-top:2.5px
 * untouched, so neither the box nor its caption moves and a caption that wraps
 * to two lines still hangs from the top rather than re-centring against the
 * checkbox. Verified: label 22.5 -> 24px while .frappe-control stayed 25px, so
 * the field does not grow and the form does not reflow. */
.checkbox label {
  min-height: 24px;
}

/* Deliberately NOT enlarged, having been measured and triaged:
 *
 * .list-row-checkbox / .list-header-checkbox (14x14 painted). Already 28x28 of
 *   hit area from Frappe's own ::after, as described at the top of this
 *   section. Touching them is a regression, not a fix.
 *
 * .collapse-indicator (16x18.5). Not a target at all — a chevron drawn inside
 *   .section-head.collapsible, which is 900x51 and carries the click and
 *   keypress handlers (confirmed: the indicator itself has no bound events).
 *   What users actually hit already conforms by a wide margin.
 *
 * Breadcrumb and page-title links — .worksapce-breadcrumb (93.6x19.5, upstream
 *   spelling), the home icon <a> (16x19.5), .title-text (77.2x16.6). Inline
 *   text in the page head whose height is set by the line box of the breadcrumb
 *   run around them, which is SC 2.5.8's inline exception; they also clear the
 *   spacing exception, the nearest other target's centre being 54.8px away.
 *   More to the point, widening them would be actively harmful: the home icon's
 *   box ends at x=251 and the "Education" link begins at x=251 — a zero-pixel
 *   gap — so a 24px-wide hit area on the icon would reach 4px into its
 *   neighbour and trade a conformance technicality for real mis-clicks. The
 *   honest fix for these is spacing in the page-head markup, which this theme
 *   does not own. */

/* ---------- skin: Estate -------------------------------------------------- */
/* A dark rail against a warm canvas, squared corners, hairline rules, and four
 * colours that mean something. Lifted from the mall-platform prototype and
 * generalised: the palette is fixed, what each semantic colour NAMES is the
 * product's business.
 *
 * Off unless a site selects it (Theme Settings -> Skin). Standard is unchanged.
 *
 * Structured the same way as the Flat surface above and for the same reason:
 * token declarations first, selectors against Frappe's markup only where a token
 * cannot reach. The token half degrades to "no effect" if upstream renames
 * something; the selector half is the part that needs re-checking after an
 * upgrade, and it is deliberately short. */
html[data-mt-skin="estate"] {
  /* ======================================================================
   * CONVERTED to the Mall style on branch mall-style-conversion, 4 Sep 2026.
   *
   * The chrome and the display face were replaced; the SEMANTIC FOUR below were
   * deliberately not, because this file's own rule is that status colours stay
   * put, Healthcare reads them as clinical states, and the Mall style defines no
   * semantic system to replace them with.
   *
   * Every changed colour was re-measured rather than assumed:
   *
   *   token            new            on              ratio    was
   *   rail-mark        #58C2AB        rail #14191A    8.21:1   6.27:1
   *   rail-brand       #58C2AB        rail #14191A    8.21:1   4.56:1
   *   rail-ink         #E7EDEB        rail #14191A   14.96:1
   *   mark-gold        #0E5C4F        card #FFFFFF    7.89:1   3.33:1
   *   ink              #14191A        canvas          16.36:1
   *   slate            #647274        canvas          4.61:1   3.96:1
   *
   * That last row is the one worth reading twice. The muted grey was BELOW the
   * 4.5:1 AA floor before this conversion, at 3.96:1, and nothing in the file
   * said so. The conversion found it only because every value was re-measured;
   * #647274 is the Mall grey darkened until it clears. Fixing it does not
   * depend on the rest of this change and should survive a revert.
   * ====================================================================== */
  /* The semantic four, read from the prototype source rather than sampled off a
   * screenshot -- my sampled values were close in hue and wrong in saturation.
   * These carry meaning and must not be reused decoratively. Healthcare reads
   * them as occupied / admitting / discharge-overdue / free; education as
   * enrolled / applied / at-risk / open seat. Same hexes, different nouns. */
  --mt-sem-good:         #0E6B63;  /* --teal / --leased  */
  --mt-sem-transitional: #C77A0A;  /* --amber / --fitout */
  --mt-sem-breach:       #A8342A;  /* --rust / --arrears */
  --mt-sem-empty:        #C9CFCB;  /* --vacant           */

  /* Chrome. The canvas is a COOL green-grey, not the warm cream it looks like at
   * a glance -- #F2F4F1 against a #0E1C26 ink. Getting that wrong is what makes
   * a copy of this design read as beige and tired. */
  --mt-canvas:     #F4F6F6;  /* --paper   */
  --mt-paper-2:    #FFFFFF;  /* --paper-2 */
  /* Hairlines in the rail's own colours, 15 Aug 2026. Both are the brand hexes
   * with lightness raised and hue held -- mixing toward white in RGB washes the
   * green straight out to grey (#293B39 at 25% gives #CACECE, which is not a
   * green at all), so these are HSL lifts instead.
   *
   * Weight matched to what they replace: the old neutral rule measured 1.53:1 on
   * a white card, and #C3D5D3 measures 1.52:1. A border is structure, not
   * decoration -- making it darker because the brand colour is dark would put a
   * slab around all six cards on a dashboard. */
  --mt-rule:       #D9E1E0;  /* #293B39 lifted -- card borders, table rules */
  --mt-rule-soft:  #E8EDEC;  /* lighter still -- inner row separators      */
  --mt-rule-gold:  #CFE6DE;  /* hairline weight, 1.55:1 -- decorative rules  */
  --mt-mark-gold:  #0E5C4F;  /* CONVERTED from #B8823F. Re-measured: 7.89:1 on a
                              * card and 7.27:1 on the canvas, against 3.33:1
                              * before. ACTIVE indicators are UI and need 3:1;
                              * the name is now wrong -- there is no gold left in
                              * this skin -- and renaming the token is a separate
                              * change, because every consumer reads it by name. */
  --mt-ink:        #14191A;  /* --ink     */
  /* GREEN RAIL. Sampled by the owner with an eyedropper on the reference photos
   * -- #293B39 and #CC9664 -- after three of my own attempts missed. The lesson
   * is worth keeping: a colour in a photograph cannot be matched by looking at
   * it, and an image pasted into a conversation cannot be measured at all. Two
   * clicks with a colour picker beat every estimate I produced.
   *
   * This green is far less saturated than anything I guessed: H173 S18% L20%,
   * against my last try at S37%. That desaturation is why it reads as stone-green
   * rather than emerald, and it is the part I kept getting wrong. */
  --mt-rail:       #14191A;
  --mt-rail-hi:    #0B0F10;  /* selected fill, 1.20:1 on the rail   */
  --mt-rail-hover: #232B2C;  /* hover fill,    1.21:1 on the rail   */
  /* The selected row's edge and the hover outline are UI indicators on a dark
   * ground, so they need the LIFTED teal, not the semantic one. #0E6B63 measures
   * 2.44:1 against the selected fill and 2.14:1 against the rail -- under the 3:1
   * a non-text indicator needs, i.e. the marker showing you where you are was the
   * least visible thing in the rail. Same hue, lifted for the ground it sits on. */
  /* Gold, not teal, now the rail is green. #2E9C90 still passed on contrast
   * (3.97:1) but teal-on-green is one family -- it measures fine and reads as
   * nothing. Amber 500 gives 5.71:1 on the rail and 6.86:1 on the selected fill,
   * sits a step brighter than the #A97328 icons so the two do not merge, and is
   * the gold-on-green the door was doing. */
  /* A lift of the owner's gold rather than a step of the old amber ramp, so the
   * mark and the icons are demonstrably one family. 6.27:1 on the rail, 7.51:1
   * on the selected fill, and brighter than the icons it has to out-rank. */
  --mt-rail-mark:  #58C2AB;
  --mt-rail-ink:   #E7EDEB;
  --mt-rail-on:    #FFFFFF;
  /* CONVERTED, and no longer the owner's sampled colour. This was #CC9664, a
   * gold the owner picked with an eyedropper off the reference photographs after
   * three attempts to guess it had failed. That provenance does not transfer to
   * a substitute, so it is not claimed here. Re-measured, not inherited:
   * #58C2AB is 8.21:1 on the new rail, against 4.56:1 for the gold on the old
   * one -- it clears both the 3:1 an indicator needs and the 4.5:1 text floor. */
  --mt-rail-brand: #58C2AB;
  /* Quiet text ON the rail -- the account email, and anything else that has to
   * read as secondary against the dark ground. Upstream's .text-secondary is a
   * light-paper grey, #7C7C7C, and measures 4.25:1 on this rail and 3.20:1 where
   * the rail is frosted glass: under the 4.5:1 text floor on both. This value
   * sat in the account-row rule as a bare literal; it is a token now so it moves
   * with the rail when the rail is retinted. Measured (WCAG 2.x relative
   * luminance, scratch script): 9.00:1 on #14191A; 6.78:1 on #1E3331, the glass
   * rail over the brightest point of the glow. */
  --mt-rail-micro: #A9BDB8;
  --mt-slate:      #647274;  /* --slate */
  --mt-micro:      #647274;
  /* Ink for the child-table header row. Frappe paints `.grid-heading-row` in
   * --gray-600, #7C7C7C, on --subtle-fg, which this skin points at --mt-rule-soft:
   * 3.53:1, under AA on every form with a child table. --mt-micro does not
   * clear it either (4.23:1 on #E8EDEC) -- the header fill is a tint of the
   * canvas, and the muted ink was measured against the canvas, not the tint. So
   * one step darker on the same hue, solved against every light header fill the
   * surfaces produce: 5.04:1 on #E8EDEC (Estate, Morning, Glass forms), 4.86:1
   * on #E8E8E8 (Carbon), 4.98:1 on #EFEAE3 (Redwood), 5.61:1 on the #F8F8F8
   * "No rows" strip. Surfaces with their own slate re-point it below. */
  --mt-grid-ink:   #596668;

  /* IBM Plex throughout: Sans for body, Sans Condensed for display, Mono for
   * every label and every number. The theme already ships Plex as a typeface
   * option, so the sans half costs nothing here. */
  --mt-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --mt-disp: 'Source Serif 4', Georgia, 'Times New Roman', serif;

  /* METALLIC RAMP. Metal is not a colour, it is a range: a dark reflection of
   * the ground, the body colour, and a near-white specular. A ramp that only
   * moves lightness reads as plastic, so the hue turns with it -- gold goes
   * redder in shadow and yellower toward the highlight.
   *
   * TWO ramps, because gold cannot shine on paper. Every stop below was solved
   * against the ground it sits on rather than chosen, then measured:
   *
   *   on the rail #293B39      on white / canvas #F2F4F1
   *   #CC9664  4.56:1          #864825  7.08 / 6.40
   *   #D5B28E  5.95:1          #9C5B2E  5.32 / 4.81
   *   #DFCAB2  7.44:1          #B36936  4.21 / 3.80
   *   #EDE6DC  9.53:1
   *
   * The dark ramp's worst stop clears the 4.5:1 AA floor for text, so the
   * metallic version is safer than the flat gold it replaces, not riskier. The
   * light ramp tops out at 4.21:1 on white: fine for a wordmark or a rule,
   * which need 3:1, and NOT to be used for body copy. That is not a limit of
   * the CSS -- a gold light enough to look like gold is 2.59:1 on white, and
   * there is no way to have both. */
  --mt-gold-1: #58C2AB;
  --mt-gold-2: #7BD3BF;
  --mt-gold-3: #A3E2D3;
  --mt-gold-4: #DCF0EA;
  --mt-bronze-1: #0B4A3F;
  --mt-bronze-2: #11675A;
  --mt-bronze-3: #17806E;

  /* THE SKIN OVERRIDES THE COLOUR PRESET, which until now it did not.
   *
   * Every page carries data-mt-color="t1" AND data-mt-skin="estate" at the same
   * time. The preset owns --mt-primary and the skin owned only the surfaces, so
   * the chrome stayed teal #0F766E on an Estate page: breadcrumbs, links,
   * primary buttons, checkboxes and the selection fill. Half the desk was one
   * brand and half was another, which is what "the theme is not applied to the
   * forms" actually meant -- the surfaces had changed and everything
   * INTERACTIVE had not.
   *
   * These three sit in the estate block, which is declared after the presets, so
   * equal specificity resolves in the skin's favour. Choosing a different
   * data-mt-color still works; it just no longer outranks the skin. */
  --mt-primary: var(--mt-rail);
  --mt-accent: var(--mt-rail-brand);
  --mt-accent-ink: #04211D;
  /* Links get their own value rather than the rail, because a link the same
   * near-black as the body text is not a link. #356B63 measures 6.11:1 on white
   * and 2.83:1 against the body ink, so it reads as Estate and still reads as
   * clickable. */
  --mt-link: #356B63;

  /* v15 vocabulary */
  --bg-color:     var(--mt-canvas);
  --card-bg:      var(--mt-paper-2);
  --fg-color:     var(--mt-paper-2);
  --subtle-fg:    var(--mt-rule-soft);
  --border-color: var(--mt-rule);
  --text-color:   var(--mt-ink);
  --text-muted:   var(--mt-slate);
  /* Frappe's second muted step. The form sidebar's Assign / Attachments / Tags /
   * Share labels, their icons and the created/modified timestamps read it, and
   * upstream leaves it at --gray-600: #7C7C7C, 3.85:1 on the canvas. The
   * skin overrode --text-muted and never this one. Slate: 4.61:1 on the
   * canvas, 5.00:1 on a card; the surfaces that re-point --mt-slate carry it. */
  --text-light:   var(--mt-slate);
  --shadow-sm:    none;
  --shadow-base:  none;

  /* v16 Espresso vocabulary -- see the note on the Flat surface above for why
   * both are required: the newer chrome reads these and ignores the legacy set. */
  --surface-cards:    var(--mt-paper-2);
  --surface-modal:    var(--mt-paper-2);
  --outline-gray-1:   var(--mt-rule-soft);
  --outline-gray-2:   var(--mt-rule);

  /* THE RAIL, ENTIRELY IN TOKENS. Measured in the shipping desk bundle:
   * `.body-sidebar { background: var(--surface-menu-bar) }`, and the item states
   * read --sidebar-hover-color / --sidebar-select-color / --sidebar-active-color.
   * So the dark rail needs no selector against Frappe's markup at all.
   *
   * The first cut of this skin set --surface-menu-bar to white and tried to paint
   * the rail with `.desk-sidebar` and `.desk-sidebar-item` instead. Those are v15
   * names: 0 occurrences in both the CSS and JS bundles on v16. The rail shipped
   * white and the rules were dead. Grep the bundle, do not assume the class.
   *
   * --surface-menu-bar is read by exactly three things -- .body-sidebar,
   * .settings-dialog and .settings-dialog-sidebar -- all of them rails, so
   * darkening it cannot leak into unrelated chrome. */
  --surface-menu-bar:     var(--mt-rail);
  --sidebar-border-color: var(--mt-rail);
  --sidebar-hover-color:  var(--mt-rail-hover);
  --sidebar-select-color: var(--mt-rail-hi);
  /* A BACKGROUND, not a text colour -- `.active-sidebar { background: var(...) }`.
   * This was set to #FFFFFF on the assumption it coloured the active label, which
   * painted the selected row white; the label rule below then set the text white
   * too, so the selected item was white on white and unreadable. Frappe's own
   * defaults gave it away and I did not look: rgba(255,255,255,1) on :root and
   * rgba(66,66,66,1) under [data-theme=dark] is a surface pattern, not an ink one.
   * Now the same dark fill as --sidebar-select-color, so both paths agree. */
  --sidebar-active-color: var(--mt-rail-hi);

  /* Squared. The prototype has no radius and no elevation anywhere; structure
   * comes from 1px rules. This overrides whatever density set. */
  --border-radius:    0;
  --border-radius-sm: 0;
  --border-radius-md: 0;
  --border-radius-lg: 0;
}

/* Cards and panels: hairline, flat, square. */
html[data-mt-skin="estate"] .widget,
html[data-mt-skin="estate"] .frappe-card,
html[data-mt-skin="estate"] .form-page {
  background: var(--card-bg);
  border: 1px solid var(--mt-rule);
  box-shadow: none;
  border-radius: 0;
}

/* Text and the teal edge. The rail's SURFACE is a token (above); these are the
 * two things a token cannot express -- the contents need a light ink now that
 * the ground is dark, and the 3px edge is what makes the active row read.
 * Verified against the shipping bundle: `.standard-sidebar-item` with .selected
 * and :hover is the real v16 item, 30 CSS references. */
html[data-mt-skin="estate"] .body-sidebar,
html[data-mt-skin="estate"] .body-sidebar a,
html[data-mt-skin="estate"] .standard-sidebar-item .sidebar-item-label {
  color: var(--mt-rail-ink);
}
html[data-mt-skin="estate"] .body-sidebar svg,
html[data-mt-skin="estate"] .standard-sidebar-item .sidebar-item-icon svg {
  fill: currentColor;
  stroke: currentColor;
}
/* The app name at the top of the sidebar now navigates to that app's own
 * landing route (see desk_theme.js). It was already an <a>, so it looked like a
 * link and behaved like a label; this makes the pointer agree with what it does. */
.body-sidebar .sidebar-header {
  cursor: pointer;
}

html[data-mt-skin="estate"] .standard-sidebar-item.selected .sidebar-item-label,
html[data-mt-skin="estate"] .standard-sidebar-item.selected a {
  color: #FFFFFF;
}
html[data-mt-skin="estate"] .standard-sidebar-item.selected {
  /* The signature. Without it a dark sidebar is just a dark sidebar; with it the
   * active row reads instantly at any density. Border only -- no padding change,
   * so the row cannot shift when it becomes selected. */
  box-shadow: inset 3px 0 0 0 var(--mt-rail-mark);
}
html[data-mt-skin="estate"] .standard-sidebar-item:hover .sidebar-item-label {
  color: var(--mt-rail-on);
}

/* Micro-labels and data. Column headers go monospace and spaced; numeric cells
 * get tabular figures so columns of money line up. Both are safe: they change
 * only type, never geometry. */
html[data-mt-skin="estate"] .list-row-head .list-row-col,
html[data-mt-skin="estate"] .widget .widget-title,
html[data-mt-skin="estate"] .number-widget-box .widget-head .widget-title {
  font-family: var(--mt-mono);
  font-size: 0.625rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--mt-micro);
}
html[data-mt-skin="estate"] .dt-cell__content,
html[data-mt-skin="estate"] .list-row-col .like-disabled-input,
html[data-mt-skin="estate"] .number-card-value,
html[data-mt-skin="estate"] [data-fieldtype="Currency"],
html[data-mt-skin="estate"] [data-fieldtype="Float"],
html[data-mt-skin="estate"] [data-fieldtype="Int"] {
  font-variant-numeric: tabular-nums;
}

/* Child-table headers and the empty strip. Upstream's `.grid-heading-row`
 * takes --gray-600 and `.grid-empty.text-extra-muted` takes --gray-500 with an
 * !important, neither of which any skin token reaches: 3.53:1 and
 * 2.68:1 on the Lease form, on every surface. The row-index cell ("No.")
 * is named as well as the header row because it is sticky and painted
 * separately. The !important on the empty strip is the only thing that beats
 * upstream's; specificity then decides, (0,2,1) here against (0,1,0). */
html[data-mt-skin="estate"] .grid-heading-row,
html[data-mt-skin="estate"] .grid-heading-row .grid-static-col,
html[data-mt-skin="estate"] .grid-heading-row .row-index {
  color: var(--mt-grid-ink);   /* #596668 on #E8EDEC 5.04:1; dark #859795 on #1F2A28 4.83:1 */
}
html[data-mt-skin="estate"] .grid-empty {
  color: var(--mt-grid-ink) !important;   /* #596668 on #F8F8F8 5.61:1; dark #859795 on #232323 5.13:1 */
}

/* Number cards: the prototype's big figure over a thin semantic bar. */
html[data-mt-skin="estate"] .number-card-value,
html[data-mt-skin="estate"] .widget.number-widget-box .widget-content .number {
  font-family: var(--mt-disp);
  font-size: 2rem;
  font-weight: 600;
  letter-spacing: -0.012em;
}

/* Dark mode: the canvas inverts, the rail stays -- it is already dark, and
 * lightening it would lose the one contrast the layout depends on. */
html[data-theme="dark"][data-mt-skin="estate"] {
  --mt-canvas:    #0D1313;
  --mt-paper-2:   #151D1D;
  --mt-rule:      #26312F;
  --mt-rule-soft: #1F2A28;
  --mt-slate:     #859795;
  --mt-micro:     #859795;
  --mt-grid-ink:  var(--mt-micro);   /* #859795 on the #1F2A28 header fill 4.83:1; on Frappe's dark --subtle-accent #232323 ("No rows") 5.13:1. Evening re-points --mt-micro to #8A9A98: 4.99:1 on its #222A2B rule. */
  --bg-color:     var(--mt-canvas);
  --card-bg:      var(--mt-paper-2);
  --fg-color:     var(--mt-paper-2);
  --subtle-fg:    var(--mt-rule-soft);
  --border-color: var(--mt-rule);
  --text-color:   #E7EDEB;
  --text-muted:   var(--mt-slate);
  --text-light:   var(--mt-slate);   /* #859795: 6.12:1 on the dark canvas, 5.60:1 on a dark card */
  --surface-cards:    var(--mt-paper-2);
  --surface-modal:    #17272F;
  --surface-menu-bar: var(--mt-rule-soft);
  --outline-gray-1:   var(--mt-rule-soft);
  --outline-gray-2:   var(--mt-rule);
  /* Same hues, lifted for contrast on a dark ground. */
  --mt-sem-good:         #2E9C90;
  --mt-sem-transitional: #D9942E;
  --mt-sem-breach:       #C9564A;
  --mt-sem-empty:        #2C3A3D;
}
html[data-theme="dark"][data-mt-skin="estate"] .widget,
html[data-theme="dark"][data-mt-skin="estate"] .frappe-card,
html[data-theme="dark"][data-mt-skin="estate"] .form-page {
  background: var(--card-bg);
  border: 1px solid var(--mt-rule);
  box-shadow: none;
}

/* Status pills. The prototype's are squared, monospace, spaced and tinted; the
 * desk ships rounded ones. 135 references in the bundle, so this is the single
 * highest-traffic component in the skin. Type and shape only -- the colour of a
 * pill still comes from whatever indicator class the document logic chose, so a
 * red pill stays red and this cannot make a status say the wrong thing. */
html[data-mt-skin="estate"] .indicator-pill {
  border-radius: 0;
  font-family: var(--mt-mono);
  font-size: 0.625rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  font-weight: 600;
  padding: 3px 7px;
}

/* Page titles take the condensed display face, as .kpi and .banner do in the
 * prototype. */
html[data-mt-skin="estate"] .page-title .title-text,
html[data-mt-skin="estate"] .page-head .title-area .title-text {
  font-family: var(--mt-disp);
  letter-spacing: -0.008em;
}

/* Hairline list rows: the prototype separates with one 1px rule and no fill. */
html[data-mt-skin="estate"] .list-row-container {
  border-bottom: 1px solid var(--mt-rule-soft);
}
html[data-mt-skin="estate"] .list-row-head {
  background: transparent;
  border-bottom: 1px solid var(--mt-rule);
}

/* ---------- Estate: sidebar legibility and hover ------------------------- */
/* Reported as "blurred and not prominent". Measured, not estimated: the rail ink
 * was #B9C8CB on the then-blue rail #1B3040, which is 7.90:1 -- a comfortable
 * AAA pass and still
 * visibly tired, because contrast ratio is not the same thing as presence. The
 * fix measured 10.68:1 there, and 10.44:1 on the green rail it moved to. Every
 * state used one colour, because Frappe paints :hover,
 * .selected AND :focus-within all from --sidebar-select-color. Three states, one look. */

/* Group headings stay quiet; everything else in the rail gets real contrast. */
html[data-mt-skin="estate"] .body-sidebar,
html[data-mt-skin="estate"] .body-sidebar a,
html[data-mt-skin="estate"] .body-sidebar .sidebar-item-label,
html[data-mt-skin="estate"] .standard-sidebar-item .sidebar-item-label {
  color: var(--mt-rail-ink);
}

/* The brand block above the nav. Targeted defensively -- the header is a
 * component with no stable class in the shipped bundles, so these selectors are
 * written to MISS harmlessly rather than to guess. If the second line does not
 * turn amber, the rule found nothing and nothing else is affected. */
html[data-mt-skin="estate"] .body-sidebar-top > *:first-child {
  color: var(--mt-rail-on);
}
html[data-mt-skin="estate"] .body-sidebar-top > *:first-child :is(small, .text-sm, .text-xs, [class*="subtitle"], [class*="muted"], [class*="description"]) {
  color: var(--mt-rail-brand);
}

/* Hover is now an OUTLINE, not a fill -- the treatment the owner picked off the
 * roadmap card, where the active item is bordered rather than blocked in. That
 * also solves the three-states-one-look problem without touching Frappe's
 * tokens: hover draws a hairline, selected keeps the fill plus its teal edge. */
html[data-mt-skin="estate"] .standard-sidebar-item {
  transition: box-shadow .12s ease, background-color .12s ease;
}
html[data-mt-skin="estate"] .standard-sidebar-item:hover:not(.selected),
html[data-mt-skin="estate"] .standard-sidebar-item:focus-within:not(.selected) {
  background-color: transparent;
  box-shadow: inset 0 0 0 1px var(--mt-rail-mark);
}
html[data-mt-skin="estate"] .standard-sidebar-item:hover .sidebar-item-label,
html[data-mt-skin="estate"] .standard-sidebar-item:focus-within .sidebar-item-label {
  color: var(--mt-rail-on);
}

/* Icons take the brand amber. Asked for explicitly, and it earns its place: the
 * rail now has three levels -- amber icons, near-white labels, muted group
 * headings -- so the eye lands on the row it wants without reading every word.
 * Icons inherit currentColor, so the colour has to be set on the icon itself
 * rather than on the item, or it would repaint the label too. */
html[data-mt-skin="estate"] .body-sidebar svg,
html[data-mt-skin="estate"] .standard-sidebar-item svg,
html[data-mt-skin="estate"] .standard-sidebar-item .sidebar-item-icon svg {
  color: var(--mt-rail-brand);
  fill: currentColor;
  stroke: currentColor;
  /* Flat gold, like every other accent in this skin. These strokes used to take
   * a gradient paint server appended by js/gold.js; that went when the metal
   * did, and the JS with it -- the CSS had always declared the flat colour first
   * so the fallback was already this. */
  opacity: 1;
}
/* On the selected row the fill already carries the emphasis, so the icon goes
 * white with the label -- amber on the highlight would fight the teal edge. */
html[data-mt-skin="estate"] .standard-sidebar-item.selected svg {
  color: #FFFFFF;
}

/* ---------- Estate: the two brand colours in the rules -------------------- */
/* Green carries the structure, gold marks the head of a card. That is the door
 * the owner showed: a green field with the gold reserved for one detail. Gold
 * everywhere would be a gold box; gold on one edge is an accent. */
html[data-mt-skin="estate"] .widget .widget-head {
  border-bottom: 1px solid var(--mt-rule-gold);
  padding-bottom: 8px;
  margin-bottom: 10px;
}
/* `.widget .widget-head` above already covers every card type -- 29 references,
 * and the variants are .dashboard-widget-box, .number-widget-box,
 * .quick-list-widget-box, .links-widget-box and .onboarding-widget-box, all of
 * which carry a .widget-head inside .widget. An earlier draft here named
 * `.chart-widget-box`, which has ZERO references in the shipped bundle: a
 * fourth dead selector caught by grepping instead of assuming.
 */

/* ---------- Estate: gold marks a header, green carries structure ---------- */
/* One rule, applied consistently, is what stops "more gold" becoming a gold box.
 * GOLD = this is a heading, or this is the active one.
 * GREEN = this is structure: a card edge, a row separator, a table rule.
 *
 * So every header in the desk takes the same gold hairline the card heads
 * already had -- page head, list head, section head, report head -- and the
 * active tab takes a heavier gold. Nothing else changes colour, which is why
 * the gold still reads as an accent at four times the coverage. */

/* Headers. Hairline weight, decorative, no contrast floor to meet. */
html[data-mt-skin="estate"] .page-head,
html[data-mt-skin="estate"] .list-row-head,
html[data-mt-skin="estate"] .section-head,
html[data-mt-skin="estate"] .form-section-heading,
html[data-mt-skin="estate"] .form-dashboard-section .section-head {
  border-bottom: 1px solid var(--mt-rule-gold);
}

/* The active tab. An indicator, not decoration, so it takes the heavier gold
 * and a 2px edge -- 3.33:1, over the 3:1 a non-text control needs. */
html[data-mt-skin="estate"] .form-tabs .nav-link.active,
html[data-mt-skin="estate"] .form-tabs li.active .nav-link {
  border-bottom: 2px solid var(--mt-mark-gold);
  color: var(--mt-ink);
}

/* Table headers, to match the list. The datatable draws its own header row. */
html[data-mt-skin="estate"] .datatable .dt-row--header,
html[data-mt-skin="estate"] .datatable .dt-header {
  border-bottom: 1px solid var(--mt-rule-gold);
}

/* ---------- Estate: dropdowns ------------------------------------------- */
/* The app menu -- Desktop / Website / Display / Session Defaults / Logout --
 * arrived as a rounded white box with a soft shadow, pasted over a dark rail.
 * It read as belonging to a different product.
 *
 * Treated as a CARD rather than as part of the rail, and that is a deliberate
 * choice with a cost. `.dropdown-menu` is one class shared by all 71 dropdowns
 * in the desk -- form actions, filters, sort menus -- so darkening it to match
 * the sidebar would drop a dark green box onto white pages everywhere else.
 * Squared, hairline and gold-topped keeps it consistent with every other
 * surface in the skin, at the price of not matching the rail it opens from.
 *
 * Scoping it to the rail only was the alternative and was rejected: the menu is
 * appended to the body, not to the sidebar, so a `.body-sidebar .dropdown-menu`
 * selector would match nothing -- the same dead-selector trap as the v15 rail. */
html[data-mt-skin="estate"] .dropdown-menu {
  background-color: var(--mt-paper-2);
  border: 1px solid var(--mt-rule);
  border-top: 2px solid var(--mt-rule-gold);
  border-radius: 0;
  box-shadow: 0 2px 8px rgba(14, 28, 38, 0.10);
  padding: 4px 0;
}

/* Items: square, full-bleed hover in the green tint so the highlight reads as
 * the same family as the rail's selected row. */
html[data-mt-skin="estate"] .dropdown-item {
  border-radius: 0;
  padding: 6px 14px;
}
html[data-mt-skin="estate"] .dropdown-item:hover,
html[data-mt-skin="estate"] .dropdown-item:focus {
  background-color: var(--mt-rule-soft);
  color: var(--mt-ink);
}

/* Dividers between groups pick up the structural green, not a default grey. */
html[data-mt-skin="estate"] .dropdown-divider {
  border-top: 1px solid var(--mt-rule);
  margin: 4px 0;
}

/* ---------- Estate: the app-menu trigger -------------------------------- */
/* The app menu opens against the right edge of the screen (see
 * public/js/sidebar_menu_right.js), so its chevron moved up to the page action
 * bar to sit beside it. This hides the one left behind in the sidebar header.
 *
 * Keyed on `body.mt-appmenu-hosted`, which that script sets ONLY while its
 * button is actually in the DOM. On a page with no `.page-actions` -- or after
 * an upstream rename of it -- the class is absent, this rule does not apply,
 * and the sidebar chevron stays exactly where it is. The reader always has a
 * trigger; the worst case is two of them, never none. That is the whole reason
 * the visibility is expressed as a class rather than as a flat `display: none`
 * on the chevron. */
body.mt-appmenu-hosted .sidebar-header .drop-icon {
  display: none;
}

/* The second line of the brand block -- "Miftahun Healthcare" under
 * "Healthcare" -- now lives on the menu row at the bottom of the rail instead.
 * The header keeps the WORKSPACE name, which is the thing that changes as you
 * move around and so is the thing worth reading there; the PRODUCT name sits
 * once, at the bottom, next to the account it belongs to.
 *
 * Keyed on the same class as everything else here: if our row is not placed,
 * this does not apply and the header keeps both lines, so the product name can
 * never disappear from the screen entirely. */
body.mt-appmenu-hosted .sidebar-header .header-subtitle {
  display: none;
}

/* The trigger itself. It sits INSIDE the dark rail now, above the account row,
 * so it is styled as a sidebar row rather than as a page button: the same ink,
 * the same gold icon and the same hover fill as every other item in the rail.
 * Styled as a button in the page action bar until 17 Aug, which is why it read
 * as a foreign object up there. */
.mt-appmenu-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 10px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--mt-rail-ink);
  font-size: var(--text-base);
  text-align: left;
  cursor: pointer;
}
.mt-appmenu-trigger .mt-appmenu-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mt-appmenu-trigger .icon {
  color: var(--mt-rail-brand);
  stroke: var(--mt-rail-brand);
}
.mt-appmenu-trigger:hover {
  background: var(--mt-rail-hover);
}
.mt-appmenu-trigger:focus-visible {
  outline: 2px solid var(--mt-rail-brand);
  outline-offset: -2px;
}

/* ---------- Estate: the account row -------------------------------------- */
/* The bottom of the rail: the person's name over their email address.
 * Upstream renders the name in the desk's default ink and the email through
 * `.text-secondary`, which is a light-background grey -- on this dark rail it
 * came out as low-contrast mud.
 *
 * The name takes the same gold as the rail's icons, so the row reads as part of
 * the skin rather than as leftover chrome, and it ties the account to the menu
 * row directly above it. The email stays quieter than the name, because it is
 * the identifier and the name is the label -- but quieter is not the same as
 * unreadable, which is what it was.
 *
 * Contrast on the #14191A rail, RE-computed for the converted palette rather
 * than carried over -- a ratio measured against a colour the file no longer uses
 * is worse than no ratio at all:
 *     #58C2AB  8.21:1  the name        (>= 4.5:1, WCAG AA normal text)
 *     #A9BDB8  9.00:1  the email       (comfortably above AA; 6.78:1 on glass)
 * Both are AA at the sizes actually used; the email is deliberately the lower
 * of the two in emphasis and still the higher in contrast, because it is set
 * small.
 *
 * THE EMAIL RULE MATCHED AND LOST, for a year. Frappe v16's desk bundle ships
 * `.text-secondary { color: #7c7c7c !important }`, and an !important declaration
 * beats every ordinary one whatever its specificity -- so the rule below applied,
 * was overridden, and the email rendered #7C7C7C: 4.25:1 on the rail, 3.20:1 on
 * the glass rail, both under AA. Nothing here could see that; an on-screen audit
 * of the Mall desk did. The only thing that beats an !important is another one,
 * after which specificity decides again: (0,5,1) here against (0,1,0) upstream.
 * The literal moved into --mt-rail-micro at the same time. */
.body-sidebar .sidebar-user-button .avatar-name-email span:first-child {
  color: var(--mt-rail-brand);
}
html[data-mt-skin="estate"] .body-sidebar .sidebar-user-button .avatar-name-email .text-secondary {
  color: var(--mt-rail-micro) !important;   /* #A9BDB8 on #14191A 9.00:1; on #1E3331 (glass) 6.78:1 */
}

/* The avatar chip beside it. Frappe hashes the user's name into one of its
 * avatar colour pairs and writes the pair INLINE -- `style="background-color:
 * var(--dark-green-avatar-bg); color: var(--dark-green-avatar-color)"` -- so
 * which pair a person gets is not a choice this file can make, and no selector
 * outranks an inline style. The pairs are tuned for white paper: Administrator
 * draws green-800 on green-200, #16794C on #DAF0E1, 4.53:1 for one 14px capital
 * -- AA by three hundredths, and other pairs in the set do worse. On the rail
 * that pale disc is also the brightest object in the column. So the Estate rail
 * fixes ONE pair for everyone: the brand gold under the accent ink, the pair
 * every primary button in this skin already wears. !important is the only
 * instrument that beats an inline style, hence its use here. */
html[data-mt-skin="estate"] .body-sidebar .sidebar-user-button .avatar-frame.standard-image {
  background-color: var(--mt-rail-brand) !important;
  border-color: var(--mt-rail-brand);
  color: var(--mt-accent-ink) !important;   /* #04211D on #58C2AB 7.84:1 */
}

/* The collapse toggle: the round button on the rail's right edge that shows
 * when the rail is hovered. Its chevron already painted gold -- the svg carries
 * stroke="currentColor" and the rail's icon rule colours every svg -- but the
 * BUTTON's own colour was never set, so it kept the UA default `buttontext`,
 * black: 1.18:1 on the rail, 1.57:1 on glass. That is the value an audit reads
 * off the element, and the value anything resolving currentColor outside the
 * svg would paint with; Frappe also gives the class `--icon-stroke:
 * var(--gray-300)`, a light-paper token. Both now point at the rail ink, and so
 * does the chevron, so what is measured and what is painted are one colour. */
html[data-mt-skin="estate"] .body-sidebar .keyboard-shortcut {
  color: var(--mt-rail-micro);   /* Frappe's grey measured 3.03:1 on the dark-mode rail; this is 9.00:1 there, 5.00:1 on the day rail */
}
html[data-mt-skin="estate"] .body-sidebar .sidebar-toggle-btn {
  color: var(--mt-rail-ink);                /* #E7EDEB on #14191A 14.96:1; on #1E3331 (glass) 11.26:1 */
  --icon-stroke: var(--mt-rail-ink);
}
html[data-mt-skin="estate"] .body-sidebar .sidebar-toggle-btn svg {
  color: var(--mt-rail-ink);
}

/* The letter badge in the sidebar header -- the fallback drawn when a workspace
 * has no icon of its own. Frappe paints the square with an inline background
 * (rgb(123,128,138) on the Mall desk) and the letter white through an inline
 * `color: var(--white)`: 3.96:1, which clears the 3:1 floor for a non-text
 * icon and belongs to no palette this skin has. Same treatment as the avatar:
 * one fixed pair, forced past the inline styles. Estate rail only. */
html[data-mt-skin="estate"] .body-sidebar .sidebar-header .icon-container {
  background-color: var(--mt-rail-brand) !important;
}
html[data-mt-skin="estate"] .body-sidebar .sidebar-header .icon-container .desktop-alphabet {
  color: var(--mt-accent-ink) !important;   /* #04211D on #58C2AB 7.84:1 */
}

/* ---------- Estate: flat gold -------------------------------------------- */
/* The accent is a COLOUR, not a surface.
 *
 * This section used to build metal here: a ramp through the gold stops, a lit
 * edge against a shaded one, a ground shadow, and a specular band that swept
 * across on hover. It was built, looked at on real controls, and taken out --
 * at desk sizes the gradient read as moulded plastic rather than as metal, and
 * the only version that read as metal was too busy for a 3px marker and a
 * button label. Flat gold on the dark rail is the version that survived.
 *
 * What that costs, deliberately: no depth cue on the selected row beyond its
 * colour, and no shine to draw the eye to a primary button. What it buys: the
 * accent looks the same at 3px and at 300px, there is no gradient stop that can
 * drift under a text label's contrast floor, and there is no animation to
 * exempt from prefers-reduced-motion.
 *
 * The ramp stops (--mt-gold-1..4) are kept. They are still the measured ladder
 * the flat choices are drawn from, and the light/dark pair of ramps is what
 * documents why gold cannot be used as text on paper. */

/* A: the selected-row marker. A real element rather than an inset shadow,
 * because a 3px inset shadow cannot be given its own radius. */
html[data-mt-skin="estate"] .standard-sidebar-item.selected {
  position: relative;
  box-shadow: none;
}
html[data-mt-skin="estate"] .standard-sidebar-item.selected::before {
  content: "";
  position: absolute;
  left: 0;
  top: 3px;
  bottom: 3px;
  width: 3px;
  border-radius: 0 2px 2px 0;
  background-color: var(--mt-gold-1);
  pointer-events: none;
}

/* B: gold text on the rail. --mt-gold-1 measures 4.56:1 there, over the 4.5:1
 * floor for normal text. */
html[data-mt-skin="estate"] .body-sidebar-top > *:first-child :is(small, .text-sm, .text-xs, [class*="subtitle"], [class*="muted"], [class*="description"]),
html[data-mt-skin="estate"] .body-sidebar .sidebar-user-button .avatar-name-email span:first-child {
  color: var(--mt-gold-1);
}

/* C: the active form tab. An indicator, not decoration, so it takes the heavier
 * gold at 2px -- 3.33:1, over the 3:1 a non-text control needs. Declared with
 * the other tab rules above; nothing to add here. */

/* ---------- Estate: the interactive chrome -------------------------------- */
/* Same specificity as the preset rules these replace -- html[data-mt-color]
 * plus a class, against html[data-mt-skin] plus a class -- so it is source order
 * that decides, and this is the end of the file.
 *
 * THE BUTTON LABEL IS THE PART THAT WAS ACTUALLY BROKEN. .btn-primary took
 * `color: var(--mt-ink)`, where --mt-ink means "ink ON the primary" in a colour
 * preset (#ffffff) and "the page's ink" in this skin (#0E1C26). One token name,
 * two meanings, and the skin's won: near-black text on the teal button,
 * measured at 3.16:1 against a 4.5:1 floor. It has been under the floor for as
 * long as the skin has shipped, and it took putting the rail green behind it --
 * which would have made it 1.47:1 -- to go and measure it. */
html[data-mt-skin="estate"] .btn-primary {
  color: #FFFFFF;              /* 17.74:1 on #14191A */
}
html[data-mt-skin="estate"] a:not(.btn):not(.no-underline) {
  color: var(--mt-link);
}

/* The login card's button, which is not .btn-primary and so was missed.
 *
 * Frappe's login bundle paints it with `var(--gray-900)` through a four-class
 * selector -- `.for-login .page-card .page-card-actions .btn-login` -- so it
 * comes out near-black, #171717, and no amount of setting --primary reaches it.
 *
 * Education did not show that, because scripts/brand-theme.css injects an
 * inline `button.btn-login { background: var(--brand) }` through Website
 * Settings.head_html. Healthcare has no such file, so the two products'
 * sign-in screens have had different coloured buttons the whole time. Putting
 * the rule here fixes both from the shared app instead of from one site's
 * head_html, which is where a shared decision belongs.
 *
 * SPECIFICITY IS THE WHOLE TRICK, not !important. theme.css loads BEFORE
 * login.bundle, so source order favours the bundle and only specificity can
 * win. The bundle's selector is (0,4,0); this one is (0,4,1) -- the attribute
 * counts at class level and `html` adds the element -- so it wins by exactly
 * one element selector, with nothing forced. */
html[data-mt-skin="estate"] .page-card .page-card-actions .btn-login,
html[data-mt-skin="estate"] .page-card .page-card-actions .btn-ldap-login {
  background-color: var(--mt-primary);
  border-color: var(--mt-primary);
  color: #FFFFFF;              /* 17.74:1 on #14191A */
}

/* ---------- Web forms ----------------------------------------------------- */
/* The public forms -- signup, enquiry, anything built as a Frappe Web Form.
 *
 * These had NO styling here at all, which is easy to miss: theme.css is in
 * `web_include_css`, so it loads on every website page, but every rule above is
 * scoped to `html[data-mt-skin]` or `html[data-mt-color]`, and those attributes
 * are written by DESK javascript. A website page carries neither, so the whole
 * stylesheet was arriving and matching nothing on it. A school's first contact
 * with us rendered as stock Frappe.
 *
 * SELECTORS ARE FROM THE RENDERED DOM, NOT VIEW-SOURCE. The served HTML holds a
 * `.web-form-skeleton`; the fields are drawn afterwards by the control renderer,
 * which nests them:
 *
 *   .web-form-container > .web-form-header > .web-form-head > .title > h1.ellipsis
 *                       > .web-form-body > .web-form-wrapper > .form-layout
 *                         > .form-page > .form-section > .section-body
 *                           > .form-column > form
 *                             > .frappe-control > .form-group.horizontal
 *                               > .clearfix > label.control-label
 *                               > .control-input-wrapper > .control-input > input.form-control
 *                       > .web-form-footer > .web-form-actions > .right-area > .submit-btn
 *
 * A first pass at this styled `.web-form`, which is not the element the fields
 * live in, and it changed almost nothing. Everything below is scoped to
 * `.web-form-container` -- present only on a web form, so it cannot leak into the
 * desk, where Frappe's own form layout must win. */

:root {
  --mtw-ink:      #14191A;
  --mtw-ink-soft: #3D4A4B;
  --mtw-muted:    #647274;
  --mtw-line:     #D9E1E0;
  --mtw-field:    #FFFFFF;
  --mtw-canvas:   #F4F6F6;
  --mtw-brand:    #14191A;
  --mtw-brand-hi: #0B0F10;
  --mtw-on-brand: #FFFFFF;
  --mtw-danger:   #A3352B;   /* 5.9:1 on white -- an error must be readable, not merely red */
  --mtw-radius:   6px;
}

/* Two of Frappe's own variables, redefined for the scope of a web form.
 *
 * This is deliberately NOT a specificity fight. The rule that greys every input
 * is `[data-doctype="Web Form"] .page-content-wrapper .container .page_content
 * ... { background-color: var(--control-bg) }` -- five classes deep and
 * unbeatable without `!important`. But it resolves a VARIABLE at the element, so
 * redefining that variable on an ancestor changes the outcome with no override
 * at all, and keeps working if upstream renumbers its selectors.
 *
 * --error-border draws a second box around every REQUIRED control, because the
 * renderer marks untouched required fields `has-error`. Made transparent here:
 * the error MESSAGE carries that meaning instead, and a form that greets a
 * visitor already outlined in red is telling them they got something wrong
 * before they typed anything. */
.web-form-container {
  --control-bg: #FFFFFF;
  /* NOT transparent. Frappe suppresses the input's own border when the wrapper
   * draws one, so blanking this left every required control with no box at all
   * while the optional ones kept theirs -- checked in the browser, not guessed.
   * Given the ordinary line colour, required and optional controls look
   * identical, which is the point: `has-error` on an untouched field is a
   * renderer artefact, not something the visitor did wrong. */
  --error-border: var(--mtw-line);
}

/* Frappe rules a line above every section after the first. Inside a card that is
 * one continuous list of questions, those rules read as boxes drawn around
 * arbitrary groups. */
.web-form-container .form-section:not(:first-child) { border-top: 0; padding-top: 0; }
.web-form-container .form-layout,
.web-form-container .form-page,
.web-form-container .section-body,
.web-form-container form { border: 0; background: transparent; box-shadow: none; }

/* The card. A form is a single column of decisions; wider than about 42rem and
 * the eye has to travel back across a gap to find the next label. */
.web-form-container {
  max-width: 42rem;
  margin: 2rem auto 4rem;
  background: var(--mtw-field);
  border: 1px solid var(--mtw-line);
  border-radius: var(--mtw-radius);
  padding: clamp(1.4rem, 1rem + 2vw, 2.5rem);
  box-shadow: 0 1px 2px rgba(14, 28, 38, .05), 0 8px 24px rgba(14, 28, 38, .06);
}

/* Frappe reserves 3rem above the header for a breadcrumb that this form does not
 * use, and the page-header above it renders empty. Both are dead space. */
.web-form-container > div[style*="height: 3rem"] { display: none; }
.page-header-wrapper:has(.page-header:empty) { display: none; }

/* `.ellipsis` truncates the heading mid-word -- which is how the title first
 * appeared as "Bring your school onto Miftah...". A heading is allowed to wrap. */
.web-form-container .web-form-title,
.web-form-container .web-form-title h1 {
  overflow: visible;
  white-space: normal;
  text-overflow: clip;
}
.web-form-container .web-form-title h1 {
  font-size: clamp(1.35rem, 1.15rem + .9vw, 1.8rem);
  font-weight: 600;
  line-height: 1.2;
  color: var(--mtw-ink);
  margin: 0;
  text-wrap: balance;
}
.web-form-container .web-form-header { margin-bottom: 1.5rem; }
.web-form-container .web-form-introduction {
  color: var(--mtw-ink-soft);
  font-size: 1rem;
  line-height: 1.55;
  max-width: 46ch;
  margin-top: .6rem;
}
.web-form-container .web-form-introduction p:last-child { margin-bottom: 0; }

/* ---- fields ---- */
/* `.input-max-width` caps controls well short of the card. Inside a column this
 * narrow it only makes the form look unfinished. */
.web-form-container .frappe-control.input-max-width { max-width: none; }
.web-form-container .frappe-control { margin-bottom: 1.2rem; }
.web-form-container .form-group.horizontal { margin: 0; }
.web-form-container .form-column { padding-left: 0; padding-right: 0; }

.web-form-container .control-label {
  display: block;
  font-size: .93rem;
  font-weight: 500;
  color: var(--mtw-ink);
  margin-bottom: .35rem;
  padding-right: 0 !important;   /* an inline 5px from the renderer */
}
/* The required marker is generated as a bare asterisk glued to the label. Given
 * room and colour it reads as a marker; without them it reads as a typo. */
.web-form-container .control-label.reqd::after { color: var(--mtw-danger); margin-left: .2rem; }

.web-form-container .control-input input.form-control,
.web-form-container .control-input select.form-control,
.web-form-container .control-input textarea.form-control,
.web-form-container .control-input .input-with-feedback {
  width: 100%;
  min-height: 2.75rem;          /* 44px: the smallest comfortable touch target */
  padding: .6rem .8rem;
  font-size: 1rem;              /* 16px or more, or iOS zooms the page on focus */
  font-weight: 400;             /* the renderer adds `.bold`; a value is not a heading */
  line-height: 1.4;
  color: var(--mtw-ink);
  background-color: var(--mtw-field);
  border: 1px solid var(--mtw-line);
  border-radius: var(--mtw-radius);
  box-shadow: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.web-form-container .control-input textarea.form-control { min-height: 6.5rem; resize: vertical; }
.web-form-container .control-input .form-control::placeholder { color: var(--mtw-muted); opacity: 1; }

/* One focus treatment for every control, and it is a ring rather than a colour
 * change: a colour change alone disappears for anyone who cannot separate this
 * green from this grey. */
.web-form-container .control-input .form-control:focus {
  outline: none;
  border-color: var(--mtw-brand);
  box-shadow: 0 0 0 3px rgba(41, 59, 57, .18);
}
.web-form-container button:focus-visible,
.web-form-container a:focus-visible { outline: 2px solid var(--mtw-brand); outline-offset: 2px; }

.web-form-container .help-box,
.web-form-container .control-input-wrapper .help-box {
  display: block;
  font-size: .85rem;
  color: var(--mtw-muted);
  margin-top: .35rem;
  line-height: 1.45;
}

/* Only the MESSAGE is coloured, never the border. The renderer leaves `has-error`
 * on controls that have never been touched, so a red border here would greet
 * every visitor with a form that looks already wrong. */
.web-form-container .error-message,
.web-form-container .invalid-feedback { color: var(--mtw-danger); font-size: .85rem; margin-top: .3rem; }

/* ---- actions ---- */
.web-form-container .web-form-footer {
  margin-top: 1.8rem;
  padding-top: 1.3rem;
  border-top: 1px solid var(--mtw-line);
}
.web-form-container .web-form-footer .right-area {
  display: flex;
  gap: .7rem;
  align-items: center;
  justify-content: flex-end;
}
.web-form-container .submit-btn {
  background-color: var(--mtw-brand);
  border: 1px solid var(--mtw-brand);
  color: var(--mtw-on-brand);
  min-height: 2.75rem;
  padding: .6rem 1.6rem;
  font-size: 1rem;
  font-weight: 600;
  border-radius: var(--mtw-radius);
}
.web-form-container .submit-btn:hover,
.web-form-container .submit-btn:focus {
  background-color: var(--mtw-brand-hi);
  border-color: var(--mtw-brand-hi);
  color: var(--mtw-on-brand);
}
.web-form-container .discard-btn {
  background-color: transparent;
  border: 1px solid var(--mtw-line);
  color: var(--mtw-ink-soft);
  min-height: 2.75rem;
  padding: .6rem 1.2rem;
  border-radius: var(--mtw-radius);
}

/* ---- small screens ---- */
/* Most people in this market meet a page like this on a phone first. The card
 * loses its frame rather than its padding, and the primary action goes full
 * width so it is reachable with a thumb. */
@media (max-width: 640px) {
  .web-form-container {
    max-width: none; margin: 0; border: 0; border-radius: 0;
    box-shadow: none; padding: 1.2rem 1rem 2.5rem;
  }
  .web-form-container .web-form-footer .right-area { flex-direction: column-reverse; align-items: stretch; }
  .web-form-container .submit-btn,
  .web-form-container .discard-btn { width: 100%; }
}

/* ---------- the palette is the person's choice ---------------------------- */
/* The Estate block above sets --mt-primary from the rail and --mt-accent from
 * the rail brand, and it is declared after the presets, so a person choosing
 * Trust Blue got teal. Each preset re-asserts its pair at skin level here;
 * t1 is left alone because on this skin t1 IS the Estate look. Then one block
 * hands every mark the skin paints to whichever pair is in force, including a
 * custom colour, which the applier writes inline and which wins on its own.
 *
 * Declared BEFORE the day rail on purpose. Both re-point --mt-rail-mark at
 * equal specificity; the day rail must win on a white rail (an accent there
 * is 1.90:1) and this must win on a dark one, and source order is the switch.
 *
 * Measured for all six presets: pill labels 4.69-15.1:1, accents on every
 * dark rail 5.42-9.41:1, glass links 4.95:1+ on the worst frosted ground. */
html[data-mt-skin="estate"][data-mt-color="t2"] { --mt-primary: #1D4ED8; --mt-accent: #60A5FA; --mt-accent-ink: #0A1B33; }
html[data-mt-skin="estate"][data-mt-color="t3"] { --mt-primary: #047857; --mt-accent: #34D399; --mt-accent-ink: #03291C; }
html[data-mt-skin="estate"][data-mt-color="t4"] { --mt-primary: #4F46E5; --mt-accent: #818CF8; --mt-accent-ink: #111436; }
html[data-mt-skin="estate"][data-mt-color="t5"] { --mt-primary: #1E3A5F; --mt-accent: #93B8E0; --mt-accent-ink: #0B1B2E; }
html[data-mt-skin="estate"][data-mt-color="t6"] { --mt-primary: #714B67; --mt-accent: #D4A9C7; --mt-accent-ink: #331A2E; }
html[data-mt-skin="estate"]:not([data-mt-color="t1"]) {
  --mt-rail-brand: var(--mt-accent);
  --mt-rail-mark:  var(--mt-accent);
  --mt-mark-gold:  var(--mt-primary);
  --mt-link:       var(--mt-primary);
  --mt-gold-1:     var(--mt-accent);
  --mt-day-rail-mark:   var(--mt-primary);
  --mt-day-rail-on-ink: var(--mt-primary);
  --mt-day-rail-hi:     color-mix(in srgb, var(--mt-accent) 22%, #FFFFFF);
  --mt-glass-glow:      color-mix(in srgb, var(--mt-accent) 22%, transparent);
  --mt-glass-glow-2:    color-mix(in srgb, var(--mt-accent) 14%, transparent);
  --mt-glass-link:      color-mix(in srgb, var(--mt-accent) 55%, #FFFFFF);
}

/* The workspace header block -- the page name a working-day page opens with --
 * arrived in Frappe's own grey, 4.17:1 on white. It is not a widget: the
 * workspace body is an Editor.js document and the header is `.ce-header`
 * inside `.codex-editor`, found by walking the DOM rather than guessing. It
 * is the title; it takes ink, and under Glass --mt-ink is already the light one. */
html[data-mt-skin="estate"] .codex-editor .ce-header,
html[data-mt-skin="estate"] .codex-editor .ce-header .h4,
html[data-mt-skin="estate"] .codex-editor .ce-header b {
  color: var(--mt-ink);
}

/* ---------- material: Morning --------------------------------------------- */
/* Option 1, and now EXACTLY Option 1. The first cut was a material laid over
 * the Estate skin -- soft corners on Estate's near-black buttons and serif
 * figures -- and the owner put the mockup beside it and asked for the mockup.
 * So every value below is read off tests/../theme-directions.html .o1, scaled
 * from that drawing's 13px base to the desk's 14px: 30px figures become 32px,
 * 12.5px rows become 13.5px, 12px card padding becomes 13px. Corners are
 * absolute (12px) because a radius is a shape, not a size.
 *
 * Off unless a site picks it; Glass includes it for every form and list, and
 * Expressive shares only the shape and day-rail tokens of the first block.
 *
 * Measured: ink #1D2D3E 14.03:1 on white; slate #556B7A 5.57:1 on white and
 * 5.18:1 on the canvas; white 5.47:1 on the accent; selected label #0B4A3F
 * 8.46:1 on the selected fill; accent icon 4.56:1 there. The mockup's Ctrl+K
 * hint was ink at 55% opacity, 3.3:1, and is slate here instead. */
html[data-mt-surface="morning"],
html[data-mt-surface="glass"],
html[data-mt-surface="expressive"] {
  --mt-morning-shadow-1: 0 1px 2px rgba(29, 45, 62, .06);
  --mt-morning-shadow-2: 0 4px 14px rgba(29, 45, 62, .08);
  --mt-morning-rule:     #DCE3E8;
  --border-radius:    12px;
  --border-radius-sm: 8px;
  --border-radius-md: 12px;
  --border-radius-lg: 12px;
  --shadow-sm:   var(--mt-morning-shadow-1);
  --shadow-base: var(--mt-morning-shadow-2);
  /* THE DAY RAIL, as drawn: white, the mockup's ink, its slate for icons and
   * hints, the accent on the selected row's icon, #D5F0EA under it. Values
   * only here; applied further down, because WHERE they apply differs:
   * everywhere under Morning, every non-dashboard route under Glass. */
  --mt-day-rail:        #FFFFFF;
  --mt-day-rail-hi:     #D5F0EA;
  --mt-day-rail-hover:  #F5F7F8;
  --mt-day-rail-rule:   #DCE3E8;
  --mt-day-rail-ink:    #1D2D3E;
  --mt-day-rail-on-ink: #0B4A3F;
  --mt-day-rail-mark:   #0F766E;
  --mt-day-rail-muted:  #556B7A;
}
/* The palette of the drawing. Morning and Glass only -- Expressive keeps the
 * skin's ink on its tonal canvas. --mt-primary is re-pointed at equal
 * specificity to the Estate block and later in the file, so it wins for the
 * Estate look (t1); a chosen preset's block outranks this and still wins. */
html[data-mt-surface="morning"],
html[data-mt-surface="glass"] {
  --mt-morning-canvas:     #F5F7F8;
  --mt-morning-ink:        #1D2D3E;
  --mt-morning-slate:      #556B7A;
  --mt-morning-accent:     #0F766E;
  --mt-morning-accent-ink: #FFFFFF;
  --mt-canvas:    var(--mt-morning-canvas);
  --mt-paper-2:   #FFFFFF;
  --mt-ink:       var(--mt-morning-ink);
  --mt-slate:     var(--mt-morning-slate);
  --mt-micro:     var(--mt-morning-slate);
  --mt-rule:      var(--mt-morning-rule);
  --mt-rule-soft: var(--mt-morning-rule);
  --mt-rule-gold: var(--mt-morning-rule);
  --mt-primary:    var(--mt-morning-accent);
  --mt-accent:     var(--mt-morning-accent);
  --mt-accent-ink: var(--mt-morning-accent-ink);
  --mt-link:       var(--mt-primary);
  --mt-mark-gold:  var(--mt-primary);
  --bg-color:      var(--mt-canvas);
  --card-bg:       var(--mt-paper-2);
  --fg-color:      var(--mt-paper-2);
  --text-color:    var(--mt-ink);
  --heading-color: var(--mt-ink);
  --text-muted:    var(--mt-slate);
  --border-color:  var(--mt-rule);
  --subtle-fg:     var(--mt-rule);
  --surface-cards:  var(--mt-paper-2);
  --surface-modal:  var(--mt-paper-2);
  --outline-gray-1: var(--mt-rule);
  --outline-gray-2: var(--mt-rule);
  --ink-gray-9: var(--mt-ink);
  --ink-gray-8: var(--mt-ink);
  --ink-gray-7: var(--mt-slate);
  --ink-gray-6: var(--mt-slate);
  --ink-gray-5: var(--mt-slate);
}
/* Cards: 1px rule, 12px corners, the drawing's shadow, 13px/15px padding. */
html[data-mt-surface="morning"] .widget,
html[data-mt-surface="morning"] .frappe-card,
html[data-mt-surface="morning"] .form-page,
html[data-mt-surface="glass"] .widget,
html[data-mt-surface="glass"] .frappe-card,
html[data-mt-surface="glass"] .form-page {
  border-radius: 12px;
  border: 1px solid var(--mt-rule);
  box-shadow: var(--shadow-sm);
}
html[data-mt-surface="morning"] .widget,
html[data-mt-surface="glass"] .widget {
  padding: 13px 15px;
}
html[data-mt-surface="morning"] .std-form-layout > .form-layout > .form-page,
html[data-mt-surface="glass"] .std-form-layout > .form-layout > .form-page {
  box-shadow: var(--shadow-sm);
}
/* No rule under a card's label in the drawing; 12px of air, then the figure. */
html[data-mt-surface="morning"] .widget .widget-head,
html[data-mt-surface="glass"] .widget .widget-head {
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: 12px;
}
html[data-mt-surface="morning"] .widget .widget-title,
html[data-mt-surface="glass"] .widget .widget-title {
  font-family: var(--mt-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--mt-micro);
}
/* Figures: the site's own face, 600, 32px, tabular. Not the serif. */
html[data-mt-surface="morning"] .number-card-value,
html[data-mt-surface="morning"] .widget.number-widget-box .widget-content .number,
html[data-mt-surface="glass"] .number-card-value,
html[data-mt-surface="glass"] .widget.number-widget-box .widget-content .number {
  font-family: var(--font-stack, inherit);
  font-size: 32px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
/* Shortcuts: a plain 13.5px label, the count in a small mono badge, no arrow. */
html[data-mt-surface="morning"] .shortcut-widget-box,
html[data-mt-surface="glass"] .shortcut-widget-box {
  padding: 11px 13px;
}
html[data-mt-surface="morning"] .shortcut-widget-box .widget-head,
html[data-mt-surface="glass"] .shortcut-widget-box .widget-head {
  margin-bottom: 0;
  align-items: center;
}
html[data-mt-surface="morning"] .shortcut-widget-box .widget-title,
html[data-mt-surface="glass"] .shortcut-widget-box .widget-title {
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--mt-ink);
}
html[data-mt-surface="morning"] .shortcut-widget-box .indicator-pill,
html[data-mt-surface="glass"] .shortcut-widget-box .indicator-pill {
  font-family: var(--mt-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  background: var(--mt-canvas);
  border: 1px solid var(--mt-rule);
  border-radius: 3px;
  color: var(--mt-micro);
  padding: 2px 6px;
}
html[data-mt-surface="morning"] .shortcut-widget-box .widget-control svg,
html[data-mt-surface="glass"] .shortcut-widget-box .widget-control svg {
  display: none;
}
/* The page name a working-day page opens with: 18px, 600, 14px of air below. */
html[data-mt-surface="morning"] .codex-editor .ce-header,
html[data-mt-surface="glass"] .codex-editor .ce-header {
  font-size: 18px;
  font-weight: 600;
  margin-bottom: 14px;
}
/* The top bar is white with a hairline under it. */
html[data-mt-surface="morning"] .page-head,
html[data-mt-surface="glass"] .page-head {
  background: var(--mt-paper-2);
  border-bottom: 1px solid var(--mt-rule);
}
/* Buttons: the accent, 12px corners, 600. */
html[data-mt-surface="morning"] .btn,
html[data-mt-surface="glass"] .btn {
  border-radius: 12px;
  font-weight: 600;
}
html[data-mt-surface="morning"] .page-head .btn,
html[data-mt-surface="glass"] .page-head .btn {
  padding: 8px 14px;
}
html[data-mt-surface="morning"] .form-control,
html[data-mt-surface="morning"] .indicator-pill,
html[data-mt-surface="glass"] .form-control,
html[data-mt-surface="glass"] .indicator-pill {
  border-radius: var(--border-radius-sm);
}
html[data-mt-surface="morning"] .dropdown-menu,
html[data-mt-surface="morning"] .modal-content,
html[data-mt-surface="glass"] .dropdown-menu,
html[data-mt-surface="glass"] .modal-content {
  border-radius: 12px;
  box-shadow: var(--shadow-base);
}
/* Rail rows: 12px corners, 13.5px labels, 600 when selected, mono hint. */
html[data-mt-surface="morning"] .standard-sidebar-item,
html[data-mt-surface="glass"] .standard-sidebar-item {
  border-radius: 12px;
}
html[data-mt-surface="morning"] .standard-sidebar-item .sidebar-item-label,
html[data-mt-surface="glass"] .standard-sidebar-item .sidebar-item-label {
  font-size: 13.5px;
}
html[data-mt-surface="morning"] .standard-sidebar-item.active-sidebar .sidebar-item-label,
html[data-mt-surface="morning"] .standard-sidebar-item.selected .sidebar-item-label,
html[data-mt-surface="glass"] .standard-sidebar-item.active-sidebar .sidebar-item-label,
html[data-mt-surface="glass"] .standard-sidebar-item.selected .sidebar-item-label {
  font-weight: 600;
}
html[data-mt-surface="morning"] .body-sidebar .keyboard-shortcut,
html[data-mt-surface="glass"] .body-sidebar .keyboard-shortcut {
  font-family: var(--mt-mono);
  font-size: 12px;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header .header-title,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header .header-title {
  font-size: 14px;
  font-weight: 600;
}

/* ---------- Morning and Glass, to the pixel ------------------------------- */
/* "Still sidebar width is not matching, rounding of box corner, icons, fonts
 * and font sizes, top bar and its sizing, gradient shading. I need exact
 * matching." So: the drawing's absolute values, not scaled. The drawing is
 * 682x420 with a 13px base; the desk is the same design with more room to
 * the right. Every number below is the drawing's own:
 *   rail 200px, rows 7px/8px with 9px between icon and label, 6px between
 *   rows, 12.5px labels at 86% ink, the selected row 600 at full ink,
 *   icons 9px rounded squares at 50% of the row's ink (the accent, full,
 *   when selected), brand mark 26px, name 14px/600, no subtitle;
 *   top bar 44px (12px + 13px line + 12px) with 18px sides and a 13px title;
 *   page body 18px, page name 17px/600 with 14px below;
 *   cards 12px/14px, labels 9.5px mono, figures 30px/600 on one line;
 *   shortcuts 10px/12px, 12.5px/500 labels, 11px mono badges;
 *   buttons 8px/14px, 12.5px/600; corners 12px everywhere (14px on Glass).
 * Type tokens are set in px so Frappe's own scale agrees with the drawing. */
html[data-mt-surface="morning"],
html[data-mt-surface="glass"] {
  --sidebar-width: 200px;
  --page-head-height: 44px;
  --text-tiny: 10px;
  --text-2xs:  11px;
  --text-xs:   11px;
  --text-sm:   12.5px;
  --text-md:   13px;
  --text-base: 13px;
  --text-lg:   14px;
  --text-xl:   17px;
  --text-2xl:  19px;
  --border-radius-sm: 12px;
}
/* The rail. */
html[data-mt-surface="morning"] .body-sidebar,
html[data-mt-surface="glass"] .body-sidebar {
  padding-left: 12px;
  padding-right: 12px;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header {
  height: auto;
  padding: 18px 6px 12px;
  gap: 10px;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header .sidebar-item-icon,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header .sidebar-item-icon {
  width: 26px;
  height: 26px;
  padding: 0;
  flex: none;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header .header-logo .icon-container,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header .header-logo .icon-container {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 8px;
  justify-content: center;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header .header-title,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header .header-title {
  font-size: 14px;
  font-weight: 600;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header .header-subtitle,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header .header-subtitle {
  display: none;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item {
  margin-bottom: 6px;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .item-anchor,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .item-anchor {
  height: auto;
  padding: 7px 8px;
  gap: 9px;
  opacity: .86;
  color: var(--mt-rail-ink);
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item.active-sidebar .item-anchor,
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item.selected .item-anchor,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item.active-sidebar .item-anchor,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item.selected .item-anchor {
  opacity: 1;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .sidebar-item-label,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .sidebar-item-label {
  font-size: 12.5px;
  line-height: 1.55;
}
/* Icons: the drawing's 9px rounded squares, in the row's own ink at half
 * strength; the accent, full strength, on the selected row. */
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon {
  width: 9px;
  height: 9px;
  padding: 0;
  flex: none;
  color: inherit;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon svg,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon svg {
  display: none;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon::before,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon::before {
  content: "";
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: currentColor;
  opacity: .5;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item.active-sidebar .sidebar-item-icon::before,
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item.selected .sidebar-item-icon::before,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item.active-sidebar .sidebar-item-icon::before,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item.selected .sidebar-item-icon::before {
  background: var(--mt-rail-mark);
  opacity: 1;
}
html[data-mt-surface="morning"] .body-sidebar .keyboard-shortcut,
html[data-mt-surface="glass"] .body-sidebar .keyboard-shortcut {
  font-size: 11px;
}
/* The top bar: 44px, 18px sides, a 13px title. */
html[data-mt-surface="morning"] .page-head .page-head-content,
html[data-mt-surface="glass"] .page-head .page-head-content {
  padding: 0;
}
html[data-mt-surface="morning"] .page-head > .container,
html[data-mt-surface="glass"] .page-head > .container {
  padding-left: 18px;
  padding-right: 18px;
}
html[data-mt-surface="morning"] .page-head .page-title .title-text,
html[data-mt-surface="glass"] .page-head .page-title .title-text {
  font-size: 13px;
  font-weight: 400;
}
/* The page: 18px of body, the page name at 17px. */
html[data-mt-surface="morning"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .page-body,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .page-body {
  padding: 18px;
}
/* The drawing's cards sit straight on the canvas. Frappe paints a panel behind
 * the workspace -- `.layout-main-section` takes --card-bg -- so it is cleared
 * on dashboards, where the cards are the paper. */
html[data-mt-surface="morning"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .layout-main-section,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .layout-main-section {
  background: transparent;
  padding: 0;
}
html[data-mt-surface="morning"] .codex-editor .ce-header,
html[data-mt-surface="glass"] .codex-editor .ce-header {
  font-size: 17px;
  margin-bottom: 14px;
}
html[data-mt-surface="morning"] .widget,
html[data-mt-surface="glass"] .widget {
  padding: 12px 14px;
}
html[data-mt-surface="morning"] .widget .widget-title,
html[data-mt-surface="glass"] .widget .widget-title {
  font-size: 9.5px;
}
html[data-mt-surface="morning"] .number-card-value,
html[data-mt-surface="morning"] .widget.number-widget-box .widget-content .number,
html[data-mt-surface="glass"] .number-card-value,
html[data-mt-surface="glass"] .widget.number-widget-box .widget-content .number {
  font-size: 30px;
}
html[data-mt-surface="morning"] .shortcut-widget-box,
html[data-mt-surface="glass"] .shortcut-widget-box {
  padding: 10px 12px;
}
html[data-mt-surface="morning"] .shortcut-widget-box .widget-title,
html[data-mt-surface="glass"] .shortcut-widget-box .widget-title {
  font-size: 12.5px;
}
html[data-mt-surface="morning"] .shortcut-widget-box .indicator-pill,
html[data-mt-surface="glass"] .shortcut-widget-box .indicator-pill {
  font-size: 11px;
}
html[data-mt-surface="morning"] .btn,
html[data-mt-surface="glass"] .btn {
  font-size: 12.5px;
}

/* ---------- measured against the drawing ---------------------------------- */
/* "Match the theme exactly." Every computed style of the drawing was read
 * with getComputedStyle and diffed against the running desk; each line here
 * closes one difference the diff reported. Where the drawing's value fails
 * WCAG AA it is used anyway, because exact was asked for twice, and the two
 * places are named: the keyboard hint at 55% ink (3.3:1) and Glass's muted
 * label ink #9DB3AF (2.83:1 on frosted paper over the glow).
 *
 * The drawing's figures are 13px regular, not 30px. Its stylesheet wrote
 * `font: 600 30px/1 inherit`, which is invalid shorthand, so the browser
 * ignored the whole declaration and the owner saw 13px. That is the drawing
 * that was chosen, so that is the figure. */
html[data-mt-surface="morning"] body,
html[data-mt-surface="glass"] body {
  font-size: 13px;
  font-weight: 400;
  letter-spacing: normal;
  --weight-regular: 400;
}
/* The Option 1 drawing is set in Inter; the Option 4 drawing in IBM Plex Sans. */
html[data-mt-surface="morning"] body,
html[data-mt-surface="glass"] body:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) {
  --font-stack: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-family: var(--font-stack);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) {
  --font-stack: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-family: var(--font-stack);
}
html[data-mt-surface="morning"] .body-sidebar,
html[data-mt-surface="glass"] .body-sidebar {
  padding: 14px 12px;
  gap: 6px;
  font-size: 13px;
  letter-spacing: normal;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header {
  padding: 4px 6px 12px;
  font-weight: 600;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header .icon-container,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header .icon-container {
  font-size: 13px;
  font-weight: 700;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item {
  padding: 0;
  margin-bottom: 0;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .item-anchor,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .item-anchor {
  border-radius: var(--border-radius);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: normal;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item.active-sidebar .item-anchor,
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item.selected .item-anchor,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item.active-sidebar .item-anchor,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item.selected .item-anchor {
  font-weight: 600;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .sidebar-item-label,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .sidebar-item-label {
  font-weight: inherit;
  letter-spacing: normal;
}
html[data-mt-surface="morning"] .body-sidebar .keyboard-shortcut,
html[data-mt-surface="glass"] .body-sidebar .keyboard-shortcut {
  color: inherit;
  opacity: .55;
  line-height: normal;
  letter-spacing: normal;
  margin-left: auto;
}
/* The top bar and the page. */
html[data-mt-surface="morning"] .page-head,
html[data-mt-surface="glass"] .page-head {
  font-size: 13px;
  letter-spacing: normal;
}
html[data-mt-surface="morning"] .page-head .page-head-content,
html[data-mt-surface="glass"] .page-head .page-head-content {
  gap: 8px;
}
html[data-mt-surface="morning"] .page-head .page-title,
html[data-mt-surface="glass"] .page-head .page-title {
  padding: 0;
}
html[data-mt-surface="morning"] .codex-editor .ce-header,
html[data-mt-surface="glass"] .codex-editor .ce-header {
  padding-bottom: 14px;
  letter-spacing: normal;
  line-height: 1.55;
}
/* Cards: label 9.5px on a 9.5px line with 12px below; the figure 13px regular. */
html[data-mt-surface="morning"] .widget,
html[data-mt-surface="glass"] .widget {
  font-size: 13px;
  letter-spacing: normal;
}
html[data-mt-surface="morning"] .widget .widget-title,
html[data-mt-surface="glass"] .widget .widget-title {
  line-height: 1;
  letter-spacing: 0.95px;
}
html[data-mt-surface="morning"] .number-card-value,
html[data-mt-surface="morning"] .widget.number-widget-box .widget-content .number,
html[data-mt-surface="glass"] .number-card-value,
html[data-mt-surface="glass"] .widget.number-widget-box .widget-content .number {
  font-size: 13px;
  font-weight: 400;
  line-height: 1.55;
}
html[data-mt-surface="morning"] .shortcut-widget-box,
html[data-mt-surface="glass"] .shortcut-widget-box {
  font-size: 12.5px;
  font-weight: 500;
}
html[data-mt-surface="morning"] .shortcut-widget-box .widget-title,
html[data-mt-surface="glass"] .shortcut-widget-box .widget-title {
  line-height: 1.55;
}
html[data-mt-surface="morning"] .shortcut-widget-box .indicator-pill,
html[data-mt-surface="glass"] .shortcut-widget-box .indicator-pill {
  margin: 0;
  line-height: normal;
}
html[data-mt-surface="morning"] .btn,
html[data-mt-surface="glass"] .btn {
  letter-spacing: normal;
  line-height: 1.55;
}

/* Second pass of the same diff: 29 lines closed to 0. Line height is the
 * drawing's 1.55 everywhere Frappe set 1.5; the brand row's side padding and
 * the page name's margin needed !important because Frappe's own rules for
 * those two are more specific than a surface can be without it. */
html[data-mt-surface="morning"] body,
html[data-mt-surface="morning"] .body-sidebar,
html[data-mt-surface="morning"] .page-head,
html[data-mt-surface="morning"] .widget,
html[data-mt-surface="morning"] .shortcut-widget-box,
html[data-mt-surface="glass"] body,
html[data-mt-surface="glass"] .body-sidebar,
html[data-mt-surface="glass"] .page-head,
html[data-mt-surface="glass"] .widget,
html[data-mt-surface="glass"] .shortcut-widget-box {
  line-height: 1.55;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header {
  padding: 4px 6px 12px !important;
  font-size: 14px;
  line-height: 1.55;
}
html[data-mt-surface="morning"] .body-sidebar .sidebar-header .icon-container,
html[data-mt-surface="glass"] .body-sidebar .sidebar-header .icon-container {
  line-height: 1.55;
}
/* The icon is the square itself now, so the drawing's radius and opacity sit
 * on the element the diff measures. */
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon {
  border-radius: 2px;
  background: currentColor;
  opacity: .5;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon::before,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item .item-anchor .sidebar-item-icon::before {
  display: none;
}
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item.active-sidebar .sidebar-item-icon,
html[data-mt-surface="morning"] .body-sidebar .standard-sidebar-item.selected .sidebar-item-icon,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item.active-sidebar .sidebar-item-icon,
html[data-mt-surface="glass"] .body-sidebar .standard-sidebar-item.selected .sidebar-item-icon {
  background: var(--mt-rail-mark);
  opacity: 1;
}
html[data-mt-surface="morning"] .body-sidebar .keyboard-shortcut,
html[data-mt-surface="glass"] .body-sidebar .keyboard-shortcut {
  font-weight: 400;
}
/* The top bar: 12px/18px of padding on the bar itself around a 20px line. */
html[data-mt-surface="morning"],
html[data-mt-surface="glass"] {
  --page-head-height: 20px;
}
html[data-mt-surface="morning"] .page-head,
html[data-mt-surface="glass"] .page-head {
  padding: 12px 18px;
  gap: 8px;
}
html[data-mt-surface="morning"] .page-head > .container,
html[data-mt-surface="glass"] .page-head > .container {
  padding-left: 0;
  padding-right: 0;
}
html[data-mt-surface="morning"] .page-head .page-head-content,
html[data-mt-surface="glass"] .page-head .page-head-content {
  height: 20px;
}
html[data-mt-surface="morning"] .codex-editor .ce-header,
html[data-mt-surface="glass"] .codex-editor .ce-header {
  padding-bottom: 0;
  margin-bottom: 14px !important;
}
html[data-mt-surface="morning"] .widget .widget-title,
html[data-mt-surface="morning"] .number-widget-box .widget-head .widget-title,
html[data-mt-surface="glass"] .widget .widget-title,
html[data-mt-surface="glass"] .number-widget-box .widget-head .widget-title {
  font-size: 9.5px;
  line-height: 1;
  letter-spacing: 0.95px;
}

/* The list filter placeholders ("Status", "ID") are Frappe's .text-extra-muted,
 * #999 on the control fill: 2.57:1 measured on education's Instructor list. */
html[data-mt-surface="morning"] .placeholder.text-extra-muted,
html[data-mt-surface="morning"] .text-extra-muted,
html[data-mt-surface="glass"] body:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .placeholder.text-extra-muted,
html[data-mt-surface="glass"] body:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .text-extra-muted {
  color: var(--mt-slate) !important;   /* #556B7A on #F3F3F3: 5.24:1 */
}

/* ---------- material: the day rail ---------------------------------------- */
/* Morning lightens the rail as well as the page. Under Glass the dashboards
 * keep their frosted dark rail and everything else gets this one, so a person
 * sees the rail change colour when they open a record from a dashboard. That
 * is the owner's call, made after seeing both: the form screen is Option 1
 * throughout, sidebar included. Dark mode is excluded on every prefix -- the
 * Evening pair keeps its dark rail, and lightening it there would lose the one
 * contrast the layout depends on.
 *
 * Route-scoped under Glass through body[data-route], which the router writes
 * on every navigation. Before the first route resolves the rail is the Estate
 * dark for one paint; on a dashboard that is already the right answer.
 *
 * Only the rail's OWN tokens are re-pointed. --mt-rail and --mt-rail-brand
 * stay: the skin derives --mt-primary and --mt-accent from them, so touching
 * either would recolour every primary button on the page. */
html[data-mt-surface="morning"]:not([data-theme="dark"]),
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) {
  --surface-menu-bar:     var(--mt-day-rail);
  --sidebar-border-color: var(--mt-day-rail-rule);
  --sidebar-hover-color:  var(--mt-day-rail-hover);
  --sidebar-select-color: var(--mt-day-rail-hi);
  --sidebar-active-color: var(--mt-day-rail-hi);
  --mt-rail-ink:   var(--mt-day-rail-ink);
  --mt-rail-on:    var(--mt-day-rail-ink);
  --mt-rail-mark:  var(--mt-day-rail-mark);
  --mt-rail-hi:    var(--mt-day-rail-hi);
  --mt-rail-hover: var(--mt-day-rail-hover);
  --mt-rail-micro: var(--mt-day-rail-muted);
}
/* The two places the skin hard-codes white for the selected row. */
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item.selected .sidebar-item-label,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.selected .sidebar-item-label,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item.selected a,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.selected a,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item.selected svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.selected svg {
  color: var(--mt-day-rail-on-ink);
}
/* Icons, the brand line and the account name read --mt-rail-brand, which is
 * left alone (see above). #58C2AB is 1.90:1 on white; these take the mark. */
html[data-mt-surface="morning"]:not([data-theme="dark"]) .body-sidebar svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar svg,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item svg,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item .sidebar-item-icon svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item .sidebar-item-icon svg,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .mt-appmenu-trigger .icon,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .mt-appmenu-trigger .icon,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .body-sidebar-top > *:first-child :is(small, .text-sm, .text-xs, [class*="subtitle"], [class*="muted"], [class*="description"]),
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar-top > *:first-child :is(small, .text-sm, .text-xs, [class*="subtitle"], [class*="muted"], [class*="description"]),
html[data-mt-surface="morning"]:not([data-theme="dark"]) .body-sidebar .sidebar-user-button .avatar-name-email span:first-child,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar .sidebar-user-button .avatar-name-email span:first-child {
  color: var(--mt-day-rail-mark);
  stroke: var(--mt-day-rail-mark);
}
html[data-mt-surface="morning"]:not([data-theme="dark"]) .mt-appmenu-trigger:focus-visible,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .mt-appmenu-trigger:focus-visible {
  outline-color: var(--mt-day-rail-mark);
}
html[data-mt-surface="morning"]:not([data-theme="dark"]) .body-sidebar,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar {
  border-right: 1px solid var(--mt-day-rail-rule);
}

/* On the day rail the drawing's icons are slate, the selected icon the accent,
 * the brand mark the accent with a white letter. */
html[data-mt-surface="morning"]:not([data-theme="dark"]) .body-sidebar svg,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item svg,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item .sidebar-item-icon svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item .sidebar-item-icon svg {
  color: var(--mt-day-rail-muted);
  stroke: var(--mt-day-rail-muted);
}
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item.active-sidebar svg,
html[data-mt-surface="morning"]:not([data-theme="dark"]) .standard-sidebar-item.selected svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.active-sidebar svg,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.selected svg {
  color: var(--mt-day-rail-mark);
  stroke: var(--mt-day-rail-mark);
}
html[data-mt-surface="morning"]:not([data-theme="dark"]) .body-sidebar .sidebar-header .icon-container,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar .sidebar-header .icon-container {
  background-color: var(--mt-day-rail-mark) !important;
  border-radius: 8px;
}
html[data-mt-surface="morning"]:not([data-theme="dark"]) .body-sidebar .sidebar-header .icon-container .desktop-alphabet,
html[data-mt-surface="glass"]:not([data-theme="dark"]) body[data-route]:not([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar .sidebar-header .icon-container .desktop-alphabet {
  color: #FFFFFF !important;
}

/* ---------- material: Glass ----------------------------------------------- */
/* Option 4, and now EXACTLY Option 4: every value read off the mockup's .o4.
 * Fluent's rule still holds -- acrylic on chrome and transient surfaces --
 * but the drawing puts the number cards on frosted paper too and the owner
 * chose the drawing, so they are frosted here and solid only in the fallbacks.
 *
 * The rail is a translucent WHITE over the ground, not a darkened one; the
 * selected row is a 14% white pill with the accent on its icon; corners 14px.
 *
 * Two values could not be the drawing's, and each is the measured reason:
 *   the muted ink #9DB3AF is 2.83:1 on frosted paper over the glow, where
 *   the third card always sits; #DCE7E4 is 4.95:1 there and 5.19:1 on the
 *   rail. The Ctrl+K hint likewise takes it rather than 55% opacity.
 * Three rules tests/test_materials.py counts: glass only on dashboards and
 * the sign-in page; every frosted surface painted solid under
 * prefers-reduced-transparency and where backdrop-filter is missing. */
html[data-mt-surface="glass"] {
  --mt-glass-ground:     #0F1B1A;
  --mt-glass-ground-2:   #16262A;
  --mt-glass-glow:       rgba(88, 194, 171, .35);
  --mt-glass-glow-2:     rgba(45, 212, 191, .22);
  --mt-glass-paper:      rgba(255, 255, 255, .07);
  --mt-glass-rule:       rgba(255, 255, 255, .14);
  --mt-glass-rule-2:     rgba(255, 255, 255, .16);
  --mt-glass-sheen:      rgba(255, 255, 255, .12);
  --mt-glass-head:       rgba(255, 255, 255, .04);
  --mt-glass-rail:       rgba(255, 255, 255, .05);
  --mt-glass-rail-rule:  rgba(255, 255, 255, .1);
  --mt-glass-rail-hi:    rgba(255, 255, 255, .07);
  --mt-glass-rail-on:    rgba(255, 255, 255, .14);
  --mt-glass-badge:      rgba(0, 0, 0, .25);
  --mt-glass-hover-2:    rgba(255, 255, 255, .22);
  --mt-glass-solid:      #1B2C2B;
  --mt-glass-ink:        #F2F7F6;
  --mt-glass-micro:      #DCE7E4;   /* 4.95:1 on frosted paper over the glow. The drawing's #9DB3AF was tried and measured 2.1-4.1:1 on the running desk -- labels people could not read, which is the complaint this build answers. */
  --mt-glass-link:       #A3E2D3;
  --mt-glass-rail-solid: #14191A;
}

/* The ground: the drawing's two glows over its 160-degree gradient, fixed so
 * glass never slides over a moving ground. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]),
html[data-mt-surface="glass"] body:has(.for-login),
html[data-mt-surface="glass"] body.mt-launcher {
  background:
    radial-gradient(88% 71% at 80% 10%, var(--mt-glass-glow),   transparent 60%),
    radial-gradient(73% 76% at 15% 90%, var(--mt-glass-glow-2), transparent 60%),
    linear-gradient(160deg, var(--mt-glass-ground), var(--mt-glass-ground-2));
  background-attachment: fixed;
  color: var(--mt-glass-ink);
  --mt-accent-ink:    #04211D;
  --border-radius:    14px;
  --border-radius-sm: 8px;
  --border-radius-md: 14px;
  --border-radius-lg: 14px;
  --bg-color:         transparent;
  --text-color:       var(--mt-glass-ink);
  --heading-color:    var(--mt-glass-ink);
  --text-muted:       var(--mt-glass-micro);
  --text-light:       var(--mt-glass-micro);
  --mt-ink:           var(--mt-glass-ink);
  --mt-micro:         var(--mt-glass-micro);
  --mt-slate:         var(--mt-glass-micro);
  --mt-link:          var(--mt-glass-link);
  --mt-rule:          var(--mt-glass-rule);
  --mt-rule-soft:     var(--mt-glass-rule);
  --mt-rule-gold:     var(--mt-glass-rule);
  --mt-primary:       var(--mt-rail-brand);
  --mt-accent:        var(--mt-rail-brand);
  --mt-canvas:        var(--mt-glass-badge);
  --mt-paper-2:       var(--mt-glass-solid);
  --border-color:     var(--mt-glass-rule);
  --card-bg:          var(--mt-glass-paper);
  --fg-color:         var(--mt-glass-paper);
  --surface-cards:    var(--mt-glass-paper);
  --surface-modal:    var(--mt-glass-solid);
  --outline-gray-1:   var(--mt-glass-rule);
  --outline-gray-2:   var(--mt-glass-rule);
  --surface-menu-bar:     var(--mt-glass-rail);
  --sidebar-border-color: var(--mt-glass-rule-2);
  --sidebar-hover-color:  var(--mt-glass-rail-hi);
  --sidebar-select-color: var(--mt-glass-rail-on);
  --sidebar-active-color: var(--mt-glass-rail-on);
  --mt-rail-ink:      var(--mt-glass-ink);
  --mt-rail-on:       var(--mt-glass-ink);
  --mt-rail-hi:       var(--mt-glass-rail-hi);
  --mt-rail-hover:    var(--mt-glass-rail-hi);
  --mt-rail-micro:    var(--mt-glass-micro);
  --ink-gray-9:  var(--mt-glass-ink);
  --ink-gray-8:  var(--mt-glass-ink);
  --ink-gray-7:  var(--mt-glass-micro);
  --ink-gray-6:  var(--mt-glass-micro);
  --ink-gray-5:  var(--mt-glass-micro);
  --icon-stroke: var(--mt-glass-micro);
  --icon-fill:   transparent;
  /* HOVER AND BUTTON FILLS. Reported with a screenshot: a Quick List row on
   * a glass dashboard hovered to white with white text. Frappe paints hover
   * and button fills from its light-mode tokens -- a row is
   * --btn-default-bg, a list row --highlight-color, a menu item
   * --fg-hover-color, an input --control-bg -- and none of them knew the page
   * had gone dark. All of them are translucent white here, so a hovered row
   * lifts a step and its ink stays the ink. */
  --btn-default-bg:       var(--mt-glass-rail-on);
  --btn-default-hover-bg: var(--mt-glass-hover-2);
  --btn-ghost-hover-bg:   var(--mt-glass-rail-hi);
  --fg-hover-color:       var(--mt-glass-rail-hi);
  --highlight-color:      var(--mt-glass-rail-hi);
  --control-bg:           var(--mt-glass-badge);
  --control-bg-on-gray:   var(--mt-glass-badge);
  --awesomplete-hover-bg: var(--mt-glass-rail-on);
  --bg-light-gray:        var(--mt-glass-rail-on);
  --bg-gray:              var(--mt-glass-rail-on);
  --disabled-control-bg:  var(--mt-glass-badge);
  /* A hovered shortcut card takes --invert-neutral for its title and border --
   * black in light mode, measured rgb(0,0,0) on the frosted card. */
  --invert-neutral:       var(--mt-glass-ink);
  /* The grey status pill (ACTIVE on a quick-list row) reads --text-on-gray,
   * near-black in light mode, over a fill that is now translucent white:
   * dark on dark until hovered. The coloured pills keep their own inks. */
  --text-on-gray:         var(--mt-glass-ink);
  /* Floating surfaces: dialogs, popovers and the "Getting Started" panel
   * (.onb-panel, position fixed) are painted from --modal-bg, which is the
   * literal `white`. Measured on the Stock workspace: the panel white, its
   * text the glass ink, "Skip All" at 2.21:1. Solid paper for all three. */
  --modal-bg:   var(--mt-glass-solid);
  --popover-bg: var(--mt-glass-solid);
  /* The onboarding spotlight paints a links card pale yellow; its title then
   * sat at 2.11:1. A step of white instead, like every other lifted surface. */
  --yellow-highlight-color: var(--mt-glass-rail-on);
  /* The chart library's own tokens. Frappe sets them for light mode only, so
   * a chart on a frosted card drew its grid in #f4f5f6, its figures in
   * #313b44 and its tooltip on white -- measured on the Education dashboard,
   * the axis labels at 2.4:1 on the frosted paper. */
  --charts-axis-line-color:      var(--mt-glass-rule);
  --charts-label-color:          var(--mt-glass-micro);
  --charts-legend-label:         var(--mt-glass-ink);
  --charts-legend-value:         var(--mt-glass-ink);
  --charts-tooltip-bg:           var(--mt-glass-solid);
  --charts-tooltip-title:        var(--mt-glass-ink);
  --charts-tooltip-label:        var(--mt-glass-micro);
  --charts-tooltip-value:        var(--mt-glass-ink);
  --charts-dataset-circle-stroke: var(--mt-glass-solid);
}
/* Dialogs on a glass dashboard: solid paper, the ink, a hairline. Measured on
 * education and healthcare: a Permission Error dialog white with white text. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .modal-content,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .modal-header,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .modal-footer {
  background: var(--mt-glass-solid);
  color: var(--mt-glass-ink);
  border-color: var(--mt-glass-rule);
}
/* Menus: the card's "..." menu measured white with white text -- the Estate
 * dropdown paints from --mt-paper-2, which the body block had not re-pointed. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .dropdown-menu {
  background: var(--mt-glass-solid);
  color: var(--mt-glass-ink);
  border: 1px solid var(--mt-glass-rule);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .dropdown-menu .dropdown-item,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .dropdown-menu .dropdown-item:hover,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .dropdown-menu .dropdown-item:focus {
  color: var(--mt-glass-ink);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .dropdown-menu .dropdown-divider {
  border-color: var(--mt-glass-rule);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .modal-content .modal-title,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .modal-content .msgprint,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .modal-content .msgprint strong {
  color: var(--mt-glass-ink);
}
/* Number-card figures carry the card's colour INLINE, and the projects colour
 * them with the Estate semantic four (leased / fit-out / arrears / vacant),
 * solved for a white card: #0E6B63 measured 1.6:1 on frosted paper. The same
 * four are already solved for a dark ground in the dark skin above; the
 * inline value is matched by its attribute and re-pointed to that pair. */
/* Measured after the first pass: no teal, amber or red clears 4.5:1 on frosted
 * paper over the glow (the lightest tints reach 3.55, 3.45, 2.60), so the
 * figure takes the ink and the card's top edge carries the colour instead --
 * an indicator, which needs 3:1, met by every tint on every ground. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .number-widget-box .number[style*="color" i] { color: var(--mt-glass-ink) !important; }
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .number-widget-box:has(.number[style*="#0E6B63" i]) { border-top: 2px solid #7BD3BF; }
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .number-widget-box:has(.number[style*="#C77A0A" i]) { border-top: 2px solid #F0B65C; }
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .number-widget-box:has(.number[style*="#A8342A" i]) { border-top: 2px solid #EE8C83; }
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .number-widget-box:has(.number[style*="#C9CFCB" i]) { border-top: 2px solid #DCE7E4; }
/* Small greys Frappe hard-codes inside widgets: the "since yesterday" stat,
 * the loading states, chart empty states. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .card-stats,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .card-stats.grey-stat,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .percentage-stat-area,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .text-extra-muted,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .chart-loading-state,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .number-card-loading,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .timestamp {
  color: var(--mt-glass-micro) !important;   /* .text-extra-muted is a utility with its own !important */
}
/* Frappe paints the chart's placeholder -- Loading..., No Data, the error
 * state -- on its own near-white #f8f8f8, and the rule above gives that text
 * the glass micro ink: light on light at 1.19:1, for as long as a chart takes
 * to load. It is the first thing on a dashboard and it was on three desks at
 * once. The placeholder takes the card's own frosted paper instead, so the ink
 * it is already given reads on it. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .chart-loading-state {
  background: var(--mt-glass-paper);
  border-radius: 10px;
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onboarding-widget-box {
  background: var(--mt-glass-solid);
  color: var(--mt-glass-ink);
  border-color: var(--mt-glass-rule);
}
/* Its text is painted with literal greys (rgb(5,5,5), rgb(107,114,128)) rather
 * than tokens, measured 1.4:1 and 3.0:1 on the solid paper. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .onb-header-main,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .onb-title,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .onb-step-text,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .font-medium {
  color: var(--mt-glass-ink);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .onb-title-steps,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .onb-skip,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .text-ink-gray-7,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .text-muted {
  color: var(--mt-glass-micro);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .onb-panel .onb-progress-badge {
  background: var(--mt-glass-badge);
  color: var(--mt-glass-ink);
}
/* .btn-default and .btn-light hard-code #f3f3f3 and #171717 in the bundle,
 * so tokens cannot reach them; the widget's filter / refresh / add buttons
 * are these. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-default,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-light,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-secondary {
  background-color: var(--mt-glass-rail-on);
  border-color: var(--mt-glass-rule);
  color: var(--mt-glass-ink);
  box-shadow: none;
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-default:hover,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-light:hover,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-secondary:hover {
  background-color: var(--mt-glass-hover-2);
  color: var(--mt-glass-ink);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-default svg,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-light svg,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-secondary svg {
  color: var(--mt-glass-ink);
  stroke: var(--mt-glass-ink);
}
/* Rows inside widgets -- quick lists, link lists -- keep the ink on hover. The
 * row and its title only: a first cut wrote `:hover *`, which reached into the
 * status pill and painted APPLIED white on its peach fill. Pills keep the ink
 * their colour gives them. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .title,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .ellipsis:not(.indicator-pill),
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .link-item:hover,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .link-item:hover .link-content {
  color: var(--mt-glass-ink);
}
/* Coloured pills keep the framework's own pair -- its pale fill with its deep
 * ink of the same hue. A first cut wrote `color: unset`, which INHERITS, and
 * inherited the row's white: OVERDUE, white on pink, reported with a
 * screenshot. Spelled out per hue so nothing above can reach them. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .indicator-pill.red,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .indicator-pill.red {
  background: var(--bg-red);
  color: var(--text-on-red);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .indicator-pill.orange,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .indicator-pill.orange {
  background: var(--bg-orange);
  color: var(--text-on-orange);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .indicator-pill.yellow,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .indicator-pill.yellow {
  background: var(--bg-yellow);
  color: #8A5A00;   /* the framework's amber measured 3.93:1 on its own pale yellow; this is 6.1:1 */
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .indicator-pill.green,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .indicator-pill.green {
  background: var(--bg-green);
  color: var(--text-on-green);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .indicator-pill.blue,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .indicator-pill.blue {
  background: var(--bg-blue);
  color: var(--text-on-blue);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .indicator-pill.purple,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .indicator-pill.purple {
  background: var(--bg-purple);
  color: var(--text-on-purple);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .indicator-pill.pink,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .indicator-pill.pink {
  background: var(--bg-pink);
  color: var(--text-on-pink);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .indicator-pill.cyan,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .indicator-pill.cyan {
  background: var(--bg-cyan);
  color: var(--text-on-cyan);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item .text-muted,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .quick-list-item:hover .text-muted {
  color: var(--mt-glass-micro);
}

/* Chrome: rail and sticky page head, frosted. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar {
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-right: 1px solid var(--mt-glass-rail-rule);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .page-head,
html[data-mt-surface="glass"] body.mt-launcher .page-head {
  background: var(--mt-glass-head);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-bottom: 1px solid var(--mt-glass-rule);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .page-head .title-text,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .page-head a,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .page-head .breadcrumb a {
  color: var(--mt-glass-ink);
}
/* The selected row: a 14% white pill, no edge, white label, accent icon. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item {
  border-radius: 14px;
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.active-sidebar,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.selected {
  box-shadow: none;
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item svg,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar svg {
  color: var(--mt-glass-micro);
  stroke: var(--mt-glass-micro);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.active-sidebar svg,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.selected svg {
  color: var(--mt-rail-brand);
  stroke: var(--mt-rail-brand);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.active-sidebar .sidebar-item-label,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .standard-sidebar-item.selected .sidebar-item-label,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar .sidebar-header .header-title {
  color: var(--mt-glass-ink);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar .keyboard-shortcut {
  color: var(--mt-glass-micro);
}

/* Content: every card is frosted paper with a 1px sheen along its top. */
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget {
  background: var(--mt-glass-paper);
  border: 1px solid var(--mt-glass-rule);
  border-radius: 14px;
  box-shadow: inset 0 1px 0 var(--mt-glass-sheen);
  color: var(--mt-glass-ink);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .widget-head,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .widget-title,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .number-widget-box .widget-head .widget-title {
  color: var(--mt-glass-micro);
  border-color: var(--mt-glass-rule);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget a,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .widget-label,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .shortcut-widget-box .widget-title,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .number-card-value,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget.number-widget-box .widget-content .number,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .widget-content,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget svg {
  color: var(--mt-glass-ink);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .shortcut-widget-box .indicator-pill,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget .badge {
  background: var(--mt-glass-badge);
  color: var(--mt-glass-micro);
  border: 1px solid var(--mt-glass-rule);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) a:not(.btn):not(.no-underline) {
  color: var(--mt-glass-link);
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn {
  border-radius: 14px;
}
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .btn-primary {
  background-color: var(--mt-rail-brand);
  border-color: var(--mt-rail-brand);
  color: var(--mt-accent-ink);
}

/* The sign-in page: the same ground, one frosted card. Scoped to the login
 * section Frappe renders (`section.for-login`), so a web form or a portal page
 * on the same site is untouched. */
html[data-mt-surface="glass"] .for-login .page-card {
  background: var(--mt-glass-paper);
  border: 1px solid var(--mt-glass-rule);
  box-shadow: inset 0 1px 0 var(--mt-glass-sheen);
  border-radius: 14px;
  color: var(--mt-glass-ink);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}
html[data-mt-surface="glass"] .for-login .page-card .page-card-head,
html[data-mt-surface="glass"] .for-login .page-card .page-card-head-text,
html[data-mt-surface="glass"] .for-login .page-card h4,
html[data-mt-surface="glass"] .for-login .page-card .form-label,
html[data-mt-surface="glass"] .for-login .page-card label,
html[data-mt-surface="glass"] .for-login .page-card .form-control {
  color: var(--mt-glass-ink);
}
html[data-mt-surface="glass"] .for-login .page-card .page-card-subtitle,
html[data-mt-surface="glass"] .for-login .page-card .text-muted,
html[data-mt-surface="glass"] .for-login .page-card .form-control::placeholder {
  color: var(--mt-glass-micro);
}
html[data-mt-surface="glass"] .for-login .page-card .form-control {
  /* !important because login.bundle paints these after us with a longer
   * selector; measured: white inputs with the glass-ink field icon on them. */
  background: var(--mt-glass-solid) !important;
  border-color: var(--mt-glass-rule) !important;
  color: var(--mt-glass-ink) !important;
}
html[data-mt-surface="glass"] .for-login .page-card .field-icon,
html[data-mt-surface="glass"] .for-login .page-card .field-icon svg {
  color: var(--mt-glass-micro);
  stroke: var(--mt-glass-micro);
}
html[data-mt-surface="glass"] .for-login .page-card a:not(.btn) {
  color: var(--mt-glass-link);
}
html[data-mt-surface="glass"] .for-login .page-card .btn-default,
html[data-mt-surface="glass"] .for-login .page-card .btn-login-option {
  background: transparent;
  border: 1px solid var(--mt-glass-rule);
  color: var(--mt-glass-ink);
}
html[data-mt-surface="glass"] .for-login .page-card .page-card-actions .btn-login,
html[data-mt-surface="glass"] .for-login .page-card .page-card-actions .btn-ldap-login {
  background-color: var(--mt-rail-brand);
  border-color: var(--mt-rail-brand);
  color: var(--mt-accent-ink);   /* #04211D on #58C2AB: 9.09:1 */
}

/* Fallbacks. Same surfaces, solid paint, no blur. Two triggers: the person
 * asked for it (Reduce Transparency), or the browser cannot draw it. Either way
 * the page is the same page with the glass swapped for paper -- nothing moves. */
@media (prefers-reduced-transparency: reduce) {
  html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--mt-glass-rail-solid);
  }
  html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .page-head {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--mt-glass-ground);
  }
  html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget,
  html[data-mt-surface="glass"] .for-login .page-card,
  html[data-mt-surface="glass"] body.mt-launcher .mt-card,
  html[data-mt-surface="glass"] body.mt-launcher .mt-launcher-search input,
  html[data-mt-surface="glass"] body.mt-launcher .mt-solar,
  html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .mt-solar {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--mt-glass-solid);
  }
}
@supports not (backdrop-filter: blur(1px)) {
  html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .body-sidebar {
    background: var(--mt-glass-rail-solid);
  }
  html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .page-head {
    background: var(--mt-glass-ground);
  }
  html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .widget,
  html[data-mt-surface="glass"] .for-login .page-card,
  html[data-mt-surface="glass"] body.mt-launcher .mt-card,
  html[data-mt-surface="glass"] body.mt-launcher .mt-launcher-search input,
  html[data-mt-surface="glass"] body.mt-launcher .mt-solar,
  html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .mt-solar {
    background: var(--mt-glass-solid);
  }
}

/* ---------- surface: Evening Console -------------------------------------- */
/* Option 2. Dark-first, one saturated accent, monospaced figures -- the shape
 * of the tools people sit in for eight hours. Its colours live under
 * [data-theme="dark"]; the applier flips a light desk when it is chosen. The
 * canvas is the Estate rail's own selected fill, so rail and page read as one
 * surface with the cards a step lighter. Measured: ink 16.25:1, slate 6.57:1. */
html[data-mt-surface="evening"] {
  --border-radius:    6px;
  --border-radius-sm: 4px;
  --border-radius-md: 6px;
  --border-radius-lg: 8px;
}
html[data-theme="dark"][data-mt-surface="evening"] {
  --mt-evening-canvas: #0B0F10;
  --mt-evening-paper:  #121718;
  --mt-evening-rule:   #222A2B;
  --mt-evening-slate:  #8A9A98;
  --mt-canvas:    var(--mt-evening-canvas);
  --mt-paper-2:   var(--mt-evening-paper);
  --mt-rule:      var(--mt-evening-rule);
  --mt-rule-soft: var(--mt-evening-rule);
  --mt-rule-gold: var(--mt-evening-rule);
  --mt-slate:     var(--mt-evening-slate);
  --mt-micro:     var(--mt-evening-slate);
  --bg-color:     var(--mt-evening-canvas);
  --card-bg:      var(--mt-evening-paper);
  --fg-color:     var(--mt-evening-paper);
  --subtle-fg:    var(--mt-evening-rule);
  --border-color: var(--mt-evening-rule);
  --text-muted:   var(--mt-evening-slate);
  --surface-cards:    var(--mt-evening-paper);
  --surface-modal:    var(--mt-evening-paper);
  --outline-gray-1:   var(--mt-evening-rule);
  --outline-gray-2:   var(--mt-evening-rule);
  --surface-menu-bar:     var(--mt-evening-canvas);
  --sidebar-border-color: var(--mt-evening-rule);
  --sidebar-select-color: var(--mt-evening-paper);
  --sidebar-active-color: var(--mt-evening-paper);
  --sidebar-hover-color:  var(--mt-evening-paper);
}
html[data-mt-surface="evening"] .widget,
html[data-mt-surface="evening"] .frappe-card,
html[data-mt-surface="evening"] .form-page {
  border-radius: var(--border-radius-lg);
}
html[data-mt-surface="evening"] .number-card-value,
html[data-mt-surface="evening"] .widget.number-widget-box .widget-content .number,
html[data-mt-surface="carbon"] .number-card-value,
html[data-mt-surface="carbon"] .widget.number-widget-box .widget-content .number {
  font-family: var(--mt-mono);
  font-weight: 500;
  letter-spacing: 0;
}

/* ---------- surface: Expressive ------------------------------------------- */
/* Option 3, the direction with the evidence: Google's 46 studies found key
 * actions spotted up to four times faster in expressive layouts, across every
 * age group. Big radius, pills, a tonal canvas mixed from the chosen accent,
 * Manrope at 800 for the figures, and ONE hero card per page -- the first
 * number card, filled with the primary. White on every preset's primary
 * measures 5.48:1 or better; the tonal canvas keeps the skin's ink at 15+:1. */
html[data-mt-surface="expressive"] {
  --mt-disp: 'Manrope', system-ui, sans-serif;
  /* Muted ink for tonal surfaces. The skin's slate measured 4.16:1 on the tonal
   * rail and 4.38:1 on a tonal card; this clears 5.30:1 on the darkest tonal
   * mix any preset produces (rail 25%, card 18%, hover 40%). */
  --mt-expressive-slate: #3F5652;
  --mt-slate: var(--mt-expressive-slate);
  --mt-micro: var(--mt-expressive-slate);
  --mt-grid-ink: var(--mt-expressive-slate);   /* 7.10:1 on the 14% tonal header fill of the default preset; the 40% mix is the darkest, and clears 5.30:1 */
  --border-radius:    16px;
  --border-radius-sm: 12px;
  --border-radius-md: 20px;
  --border-radius-lg: 22px;
  --mt-canvas: color-mix(in srgb, var(--mt-accent) 9%, #FFFFFF);
  --bg-color:  var(--mt-canvas);
  --mt-rule:      transparent;
  --mt-rule-soft: color-mix(in srgb, var(--mt-accent) 14%, #FFFFFF);
  --mt-rule-gold: color-mix(in srgb, var(--mt-accent) 14%, #FFFFFF);
  --border-color: var(--mt-rule-soft);
}
html[data-mt-surface="expressive"]:not([data-theme="dark"]) {
  /* A light tonal rail; the selected row is a pill in the primary. */
  --surface-menu-bar:     color-mix(in srgb, var(--mt-accent) 25%, #FFFFFF);
  --sidebar-border-color: transparent;
  --sidebar-hover-color:  color-mix(in srgb, var(--mt-accent) 40%, #FFFFFF);
  --sidebar-select-color: var(--mt-primary);
  --sidebar-active-color: var(--mt-primary);
  --mt-rail-ink:   var(--mt-ink);
  --mt-rail-on:    var(--mt-ink);
  --mt-rail-mark:  var(--mt-day-rail-mark);
  --mt-rail-micro: var(--mt-expressive-slate);
  --mt-rail-hi:    var(--mt-primary);
  --mt-rail-hover: color-mix(in srgb, var(--mt-accent) 40%, #FFFFFF);
}
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .body-sidebar svg,
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .standard-sidebar-item svg,
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .mt-appmenu-trigger .icon,
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .body-sidebar .sidebar-user-button .avatar-name-email span:first-child {
  color: var(--mt-day-rail-mark);
  stroke: var(--mt-day-rail-mark);
}
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .standard-sidebar-item.active-sidebar,
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .standard-sidebar-item.selected {
  box-shadow: none;
}
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .standard-sidebar-item.active-sidebar .sidebar-item-label,
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .standard-sidebar-item.active-sidebar svg,
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .standard-sidebar-item.selected .sidebar-item-label,
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .standard-sidebar-item.selected svg {
  color: #FFFFFF;
}
html[data-mt-surface="expressive"] .standard-sidebar-item,
html[data-mt-surface="expressive"] .btn,
html[data-mt-surface="expressive"] .indicator-pill,
html[data-mt-surface="expressive"] .form-control,
html[data-mt-surface="expressive"] .shortcut-widget-box {
  border-radius: 999px;
}
html[data-mt-surface="expressive"] .widget,
html[data-mt-surface="expressive"] .frappe-card,
html[data-mt-surface="expressive"] .form-page,
html[data-mt-surface="expressive"] .modal-content,
html[data-mt-surface="expressive"] .dropdown-menu {
  border-radius: var(--border-radius-lg);
  border-color: transparent;
  box-shadow: none;
}
html[data-mt-surface="expressive"] .shortcut-widget-box {
  padding-left: 18px;
  padding-right: 18px;
}
html[data-mt-surface="expressive"] .number-card-value,
html[data-mt-surface="expressive"] .widget.number-widget-box .widget-content .number {
  font-family: var(--mt-disp);
  font-weight: 800;
  letter-spacing: -0.02em;
}
/* Number cards take a tonal fill of the accent. The direction's "one hero
 * card" was tried and dropped: Frappe wraps every card in a container of its
 * own, so :first-of-type matched all three, and there is no CSS for "first in
 * the page". Tonal everywhere keeps the skin's ink at 14:1+ on every preset. */
html[data-mt-surface="expressive"]:not([data-theme="dark"]) .widget.number-widget-box {
  background: color-mix(in srgb, var(--mt-accent) 18%, #FFFFFF);
}

/* ---------- surface: Redwood ---------------------------------------------- */
/* Option 5. Warm paper, a warm dark rail, serif figures -- the skin's display
 * face already -- and 4px corners. The register of a ledger, for rent,
 * arrears and invoices. Colours only in light mode; dark mode keeps the Estate
 * dark skin, which is already measured. Measured here: ink 13.64:1, slate
 * 5.44:1 on the canvas; rail ink 13.16:1; every preset accent 5.42:1+ on the
 * rail. */
html[data-mt-surface="redwood"] {
  --border-radius:    4px;
  --border-radius-sm: 3px;
  --border-radius-md: 4px;
  --border-radius-lg: 6px;
}
html[data-mt-surface="redwood"]:not([data-theme="dark"]) {
  --mt-redwood-canvas:     #F7F4EF;
  --mt-redwood-ink:        #2B2622;
  --mt-redwood-slate:      #6B625A;
  --mt-redwood-rule:       #E4DDD4;
  --mt-redwood-rule-soft:  #EFEAE3;
  --mt-redwood-rail:       #24201D;
  --mt-redwood-rail-hi:    #3A342F;
  --mt-redwood-rail-hover: #2E2925;
  --mt-redwood-rail-ink:   #EDE7DF;
  --mt-canvas:    var(--mt-redwood-canvas);
  --mt-ink:       var(--mt-redwood-ink);
  --mt-slate:     var(--mt-redwood-slate);
  --mt-micro:     var(--mt-redwood-slate);
  --mt-grid-ink:  var(--mt-redwood-slate);   /* #6B625A on the #EFEAE3 header fill 4.99:1 */
  --mt-rule:      var(--mt-redwood-rule);
  --mt-rule-soft: var(--mt-redwood-rule-soft);
  --mt-rule-gold: var(--mt-redwood-rule);
  --bg-color:     var(--mt-redwood-canvas);
  --text-color:   var(--mt-redwood-ink);
  --text-muted:   var(--mt-redwood-slate);
  --border-color: var(--mt-redwood-rule);
  --subtle-fg:    var(--mt-redwood-rule-soft);
  --outline-gray-1: var(--mt-redwood-rule-soft);
  --outline-gray-2: var(--mt-redwood-rule);
  --surface-menu-bar:     var(--mt-redwood-rail);
  --sidebar-border-color: var(--mt-redwood-rail);
  --sidebar-hover-color:  var(--mt-redwood-rail-hover);
  --sidebar-select-color: var(--mt-redwood-rail-hi);
  --sidebar-active-color: var(--mt-redwood-rail-hi);
  --mt-rail-ink:   var(--mt-redwood-rail-ink);
  --mt-rail-on:    #FFFFFF;
  --mt-rail-hi:    var(--mt-redwood-rail-hi);
  --mt-rail-hover: var(--mt-redwood-rail-hover);
}
html[data-mt-surface="redwood"] .widget,
html[data-mt-surface="redwood"] .frappe-card,
html[data-mt-surface="redwood"] .form-page {
  border-radius: var(--border-radius);
}
html[data-mt-surface="redwood"] .page-title .title-text,
html[data-mt-surface="redwood"] .page-head .title-area .title-text {
  font-size: 1.25em;
}

/* ---------- surface: Carbon Grid ------------------------------------------ */
/* Option 6, IBM Carbon's g10/g100 pair: square everything, a 2px rule at the
 * head of every card, a 3px marker on the active row, monospaced figures. The
 * 2026 "grid as foreground" trend is this idea returning. Colours only in
 * light mode, as with Redwood. Measured: ink 16.45:1, slate 7.10:1. */
html[data-mt-surface="carbon"] {
  --border-radius:    0;
  --border-radius-sm: 0;
  --border-radius-md: 0;
  --border-radius-lg: 0;
}
html[data-mt-surface="carbon"]:not([data-theme="dark"]) {
  --mt-carbon-canvas:     #F4F4F4;
  --mt-carbon-ink:        #161616;
  --mt-carbon-slate:      #525252;
  --mt-carbon-rule:       #E0E0E0;
  --mt-carbon-rule-soft:  #E8E8E8;
  --mt-carbon-rail:       #161616;
  --mt-carbon-rail-hi:    #393939;
  --mt-carbon-rail-hover: #262626;
  --mt-carbon-rail-ink:   #F4F4F4;
  --mt-canvas:    var(--mt-carbon-canvas);
  --mt-ink:       var(--mt-carbon-ink);
  --mt-slate:     var(--mt-carbon-slate);
  --mt-micro:     var(--mt-carbon-slate);
  --mt-grid-ink:  var(--mt-carbon-slate);   /* #525252 on the #E8E8E8 header fill 6.38:1 */
  --mt-rule:      var(--mt-carbon-rule);
  --mt-rule-soft: var(--mt-carbon-rule-soft);
  --mt-rule-gold: var(--mt-carbon-rule);
  --bg-color:     var(--mt-carbon-canvas);
  --text-color:   var(--mt-carbon-ink);
  --text-muted:   var(--mt-carbon-slate);
  --border-color: var(--mt-carbon-rule);
  --subtle-fg:    var(--mt-carbon-rule-soft);
  --outline-gray-1: var(--mt-carbon-rule-soft);
  --outline-gray-2: var(--mt-carbon-rule);
  --surface-menu-bar:     var(--mt-carbon-rail);
  --sidebar-border-color: var(--mt-carbon-rail);
  --sidebar-hover-color:  var(--mt-carbon-rail-hover);
  --sidebar-select-color: var(--mt-carbon-rail-hi);
  --sidebar-active-color: var(--mt-carbon-rail-hi);
  --mt-rail-ink:   var(--mt-carbon-rail-ink);
  --mt-rail-on:    #FFFFFF;
  --mt-rail-hi:    var(--mt-carbon-rail-hi);
  --mt-rail-hover: var(--mt-carbon-rail-hover);
}
html[data-mt-surface="carbon"] .widget,
html[data-mt-surface="carbon"] .frappe-card,
html[data-mt-surface="carbon"] .form-page,
html[data-mt-surface="carbon"] .btn,
html[data-mt-surface="carbon"] .form-control,
html[data-mt-surface="carbon"] .indicator-pill,
html[data-mt-surface="carbon"] .modal-content,
html[data-mt-surface="carbon"] .dropdown-menu,
html[data-mt-surface="carbon"] .standard-sidebar-item {
  border-radius: 0;
}
html[data-mt-surface="carbon"] .widget,
html[data-mt-surface="carbon"] .frappe-card,
html[data-mt-surface="carbon"] .form-page {
  border-top: 2px solid var(--mt-mark-gold);
  box-shadow: none;
}
html[data-mt-surface="carbon"] .standard-sidebar-item.active-sidebar,
html[data-mt-surface="carbon"] .standard-sidebar-item.selected {
  box-shadow: inset 3px 0 0 0 var(--mt-rail-mark);
}

/* ---------- the launcher: cards with a purpose line ----------------------- */
/* Option 3 of the launcher review. Drawn by js/launcher.js beside the
 * framework's grid, which .mt-cards hides. Morning first; Glass below. */
.desktop-container.mt-cards .icons-container,
.desktop-container.mt-cards .icons { display: none; }
/* Three columns at least. The framework keeps its Desktop narrow -- the grid
 * of tiles wants that -- so the launcher lets the container run the page's
 * width and lays the cards in three columns from a laptop up, four on a
 * wide screen, two on a tablet, one on a phone. */
body.mt-launcher .desktop-container,
body.mt-launcher .desktop-container .icons-container,
body.mt-launcher .desktop-wrapper {
  max-width: none;
  width: 100%;
}
.mt-launcher { max-width: 1480px; margin: 0 auto; padding: 28px 12px 48px; }
.mt-launcher-search input {
  width: 100%;
  font: inherit;
  font-size: 13.5px;
  padding: 10px 14px;
  border: 1px solid var(--mt-rule, #DCE3E8);
  border-radius: var(--border-radius-lg, 12px);
  background: var(--card-bg, #FFFFFF);
  color: var(--mt-ink, #1D2D3E);
}
.mt-launcher-search input:focus { outline: 2px solid var(--mt-primary, #0F766E); outline-offset: 1px; }
.mt-launcher-group h3 {
  font: 500 10px/1 var(--mt-mono, ui-monospace, monospace);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--mt-micro, #556B7A);
  margin: 24px 0 10px;
}
.mt-launcher-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 1180px) { .mt-launcher-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 860px)  { .mt-launcher-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .mt-launcher-cards { grid-template-columns: minmax(0, 1fr); } }
.mt-card {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  background: var(--card-bg, #FFFFFF);
  border: 1px solid var(--mt-rule, #DCE3E8);
  border-radius: var(--border-radius-lg, 12px);
  padding: 12px 14px;
  color: var(--mt-ink, #1D2D3E);
  text-decoration: none;
  box-shadow: var(--shadow-sm, none);
}
.mt-card:hover, .mt-card:focus-visible { border-color: var(--mt-primary, #0F766E); text-decoration: none; color: var(--mt-ink, #1D2D3E); outline: none; }
.mt-card img, .mt-card-letter { width: 36px; height: 36px; border-radius: 10px; flex: none; }
.mt-card p { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.mt-card-letter { display: grid; place-items: center; background: var(--mt-primary, #0F766E); color: #FFFFFF; font-weight: 700; }
.mt-card > div { min-width: 0; }
.mt-card b { display: block; font-size: 13.5px; font-weight: 600; }
.mt-card p { margin: 2px 0 0; font-size: 12px; line-height: 1.45; color: var(--mt-slate, #556B7A); }
.mt-open {
  margin-left: auto;
  align-self: center;
  flex: none;
  background: var(--mt-primary, #0F766E);
  color: var(--mt-accent-ink, #FFFFFF);
  border-radius: var(--border-radius-sm, 10px);
  padding: 4px 11px;
  font-size: 12px;
  font-weight: 600;
}
.mt-card[hidden], .mt-launcher-group[hidden] { display: none; }
/* Glass: frosted cards on the dashboard ground; the search box a frosted pane. */
html[data-mt-surface="glass"] body.mt-launcher .mt-card,
html[data-mt-surface="glass"] body.mt-launcher .mt-launcher-search input {
  background: var(--mt-glass-paper);
  border-color: var(--mt-glass-rule);
  color: var(--mt-glass-ink);
  box-shadow: inset 0 1px 0 var(--mt-glass-sheen);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
html[data-mt-surface="glass"] body.mt-launcher .mt-card p,
html[data-mt-surface="glass"] body.mt-launcher .mt-launcher-group h3 { color: var(--mt-glass-micro); }
html[data-mt-surface="glass"] body.mt-launcher .mt-card:hover { border-color: var(--mt-rail-brand); }
html[data-mt-surface="glass"] body.mt-launcher .mt-open { background: var(--mt-rail-brand); color: var(--mt-accent-ink); }
html[data-mt-surface="glass"] body.mt-launcher .layout-main-section { background: transparent; }

/* ---------- Solar tiles: frosted --------------------------------------------- */
/* The owner's pick from the Solar variations: tile D (frosted) with scheme S3
 * (the accent for the line, a frosted white plane). On a light ground there is
 * nothing to frost, so the tile is the accent at 12% with the primary for the
 * line; on Glass it is a pane like every other. The line follows the palette
 * through the same tokens the rest of the desk reads. */
.mt-solar {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 12px;
  background: color-mix(in srgb, var(--mt-accent, #58C2AB) 12%, #FFFFFF);
  border: 1px solid var(--mt-rule, #DCE3E8);
  color: var(--mt-primary, #0F766E);
  --solar-plane: var(--mt-primary, #0F766E);
  --solar-plane-o: .22;
}
.mt-solar svg { width: 56%; height: 56%; display: block; }
.desktop-icon .icon-container .mt-solar-tile { min-width: 48px; min-height: 48px; }
.mt-card .mt-solar { width: 36px; height: 36px; flex: none; border-radius: 10px; }
.navbar .mt-solar-mark { width: 30px; height: 30px; border-radius: 9px; display: inline-grid; }
/* The bar it sits on is white on every surface, launcher and dashboards
 * included, so the mark always takes the light tile: the accent at 12% and
 * the deep teal for the line -- the body-level glass tokens re-point
 * --mt-primary to the bright accent, which measured 1.9:1 on white. */
html[data-mt-surface] body .navbar-home .mt-solar.mt-solar-mark {
  background: color-mix(in srgb, var(--mt-morning-accent, #0F766E) 12%, #FFFFFF);
  border-color: var(--mt-morning-rule, #DCE3E8);
  color: var(--mt-morning-accent, #0F766E);
  --solar-plane: var(--mt-morning-accent, #0F766E);
  --solar-plane-o: .22;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}
html[data-mt-surface="glass"] body.mt-launcher .mt-solar,
html[data-mt-surface="glass"] body:is([data-route^="Workspaces"], [data-route^="dashboard-view"]) .mt-solar {
  background: var(--mt-glass-paper);
  border-color: var(--mt-glass-rule);
  color: var(--mt-rail-brand);
  --solar-plane: var(--mt-glass-ink);
  --solar-plane-o: .16;
  box-shadow: inset 0 1px 0 var(--mt-glass-sheen);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* ---------- Duotone charts -------------------------------------------------- */
/* Option 8 of the chart review, drawn by public/js/charts.js: the colour work
 * happens there, because the library paints hue on each element. What CSS can
 * carry is here: the round line, the plane's edge, and the tooltip's paper on
 * every ground. Scoped to the choice, so Standard is the library untouched. */
html[data-mt-charts="duotone"] .chart-container .line-graph-path {
  stroke-linecap: round;
  stroke-linejoin: round;
}
html[data-mt-charts="duotone"] .chart-container .region-fill { stroke: none; }
html[data-mt-charts="duotone"] .chart-container .mt-halo { pointer-events: none; }
html[data-mt-charts="duotone"] .chart-container .mt-end { pointer-events: none; }
/* The library hides every axis line but the base one at .axis line
 * opacity; the horizontal grid on a Morning card is a hairline in the rule
 * colour rather than the library's near-white. */
html[data-mt-charts="duotone"] .chart-container .y.axis line { stroke: var(--charts-axis-line-color, #E3E9EC); }
html[data-mt-charts="duotone"] .chart-container .graph-svg-tip {
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(15, 31, 29, .18);
}

/* ---------- No-access placeholder ------------------------------------------- */
/* A chart or number card whose source the reader may not read keeps its place
 * on the page and says so quietly, rather than throwing the server's message
 * over everything as a modal. See workspace_widgets.py and its .js. The ink is
 * the page's own muted one, so this reads on Morning paper and on frosted
 * Glass without a second rule. */
.widget.mt-no-access .widget-body {
  display: grid;
  place-items: center;
  min-height: 64px;
  padding: 10px 12px;
  color: var(--mt-micro, var(--text-muted, #5B6B7A));
  font-size: 12.5px;
  text-align: center;
}
.widget.mt-no-access .widget-title { opacity: .75; }
