/* iSystems portal — design tokens and the few things MudBlazor's theme cannot express.
   Same token family as the public site (IsystemsWebSite/wwwroot/css/admin.css). Colours live in
   IsyTheme.cs; what is repeated here is only what CSS needs directly. */
:root {
  --isy-navy: #171E30;          /* brand chrome: the site's topbar and admin sidebar, and our app bar */
  --isy-green: #0D8359;         /* brand accent: fills only */
  --isy-green-deep: #0A6647;    /* the same green as TEXT — #0D8359 is under AA on the grey ground */
  --isy-green-tint: #E6F4EE;
  --isy-green-bright: #3FBE8C;  /* the green that survives on navy and in dark mode */
  --isy-cream: #FBF9EE;         /* the site's "featured" ground — here it marks a pinned notice */
  --isy-ground: #F4F6F8;
  --isy-brass: #9A6B1A;      /* reserved for activation keys and machine ids — nothing else */
  --isy-brass-soft: #F5ECDA;
  --isy-mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;
}

html, body { font-family: "IBM Plex Sans Arabic", "IBM Plex Sans", "Segoe UI", system-ui, sans-serif; }
body { background: var(--isy-ground); font-variant-numeric: tabular-nums; }

/* the signature: an activation key rendered like the printed license label it becomes */
.isy-key {
  display: inline-flex; align-items: center; gap: .45em;
  font-family: var(--isy-mono); font-size: 1.05rem; letter-spacing: .06em;
  direction: ltr; unicode-bidi: isolate;
  color: var(--isy-brass); background: var(--isy-brass-soft);
  border: 1px solid color-mix(in srgb, var(--isy-brass) 35%, transparent);
  border-radius: 4px; padding: .25em .7em;
  /* the notch is a hole punched in the label, so it must be the colour of whatever the chip sits on
     — the card, not the page. Using the page ground left pale holes on white cards, and would have
     punched light holes in a dark chip. */
  background-image: radial-gradient(circle at 0 50%, var(--mud-palette-surface) .35em, transparent .36em),
                    radial-gradient(circle at 100% 50%, var(--mud-palette-surface) .35em, transparent .36em);
  background-repeat: no-repeat;
}
.isy-key--lg { font-size: 1.5rem; padding: .35em 1em; }
.isy-mono { font-family: var(--isy-mono); direction: ltr; unicode-bidi: isolate; }

/* Numbers in tables read as columns. text-align is PHYSICAL on purpose: in the Arabic UI "end" is the
   LEFT edge, so the amounts lined up on their first digit and the decimal points came out ragged —
   304,600.00 and 72,000.00 stopped sharing a units column. Money is read from its last digits, so it stays
   flush right in both languages, and a sub-line under an amount lands on that same edge whatever dir= it
   carries (the age caption is dir="ltr", and with a logical end it drifted to the opposite side). */
.isy-num { font-family: var(--isy-mono); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
/* "57 / 65" in a column: a count and the total it came out of. Plain right-aligned text lines up the
   TOTAL and leaves the number the reader is after — how many licences are live — starting at a different
   x on every row, so the column cannot be scanned. Pinning the last track to a fixed width puts the slash
   on one vertical line instead: the count ends at it, the total starts after it, and tabular figures keep
   1 and 7 the same width. The track is the width of a two-digit total — what the data actually holds — so
   the pair still ends on the column edge; minmax, not a flat 2ch, lets a bigger total widen its own row. */
.isy-ratio { display: inline-grid; grid-template-columns: auto auto minmax(2ch, auto); align-items: baseline;
             font-variant-numeric: tabular-nums; white-space: nowrap; }
.isy-ratio__n { text-align: right; }
.isy-ratio__s { padding-inline: .3rem; opacity: .45; }
/* The total is the context, not the reading: it stays a step behind the count it divides. */
.isy-ratio__d { text-align: left; opacity: .6; }

/* second line under an amount: the age, the credit — same right edge, quieter */
.isy-num__s { display: block; font-size: .75rem; line-height: 1.35; color: var(--mud-palette-text-secondary); }
/* Filter strip above a list: one bordered bar, every control on the same line, the primary action pinned
   to the far end. Search and pickers are both outlined+dense so their boxes share a height and a baseline —
   mixing MudBlazor's underline and outlined variants is what made the row look ragged. */
.isy-toolbar { display:flex; align-items:center; flex-wrap:wrap; gap:.6rem; padding:.55rem .7rem; border:1px solid var(--mud-palette-lines-default); border-radius:8px; background:var(--mud-palette-surface); }
/* MudBlazor reserves a floating-label gap with "margin-top:8px !important"; inside the bar the labels sit
   in the outlined notch, so the gap only pushes the pickers below the search box's baseline. */
.isy-toolbar .mud-input-control { margin-top:0 !important; margin-bottom:0 !important; }
.isy-toolbar__search { flex:1 1 200px; max-width:300px; }
.isy-toolbar__pick { flex:0 0 auto; width:130px; display:flex; align-items:center; }
.isy-toolbar__pick--wide { width:210px; }
.isy-toolbar__pick > .mud-select { width:100%; margin:0; }
.isy-toolbar__sep { align-self:center; width:1px; height:22px; background:var(--mud-palette-lines-default); margin-inline:.15rem; }
.isy-toolbar__count { font-size:.8rem; font-variant-numeric:tabular-nums; white-space:nowrap; }
@media (max-width: 900px) { .isy-toolbar__sep { display:none; } .isy-toolbar__search { max-width:none; } }

/* Second line in a table cell: what the row means, under the key it belongs to. Two lines, not one —
   an edition label is a sentence ("اصدار مخصص لمحمد النحتة - اضافة الخصم"), and cutting it at 34
   characters threw away the half that named the customer. The rest is one click away, in the row's panel. */
.isy-cellsub { font-size:.75rem; line-height:1.4; color:var(--mud-palette-text-secondary); max-width:52ch;
               display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }

/* One release a customer runs, on the customization page. The edition is the heading — it is the only text
   that says whose build this is — and the version, the date and the counts are its caption.
   (These cards were first drawn inside an expandable row on the program page. That panel was a workaround for
   the wrong grain: it hung a code's releases under a code's row. /admin/customizations/{id} is the page it was
   standing in for, so the panel and its .isy-detail* chrome are gone and only the cards remain.) */
.isy-rels { display:grid; grid-template-columns:repeat(auto-fill, minmax(300px, 1fr)); gap:.6rem; }
/* The download sits at the card's foot, under a hairline, at the reading end's far side; cards in a row keep one height. */
.isy-rel__foot { margin-top:auto; padding-top:.55rem; border-top:1px solid var(--mud-palette-lines-default); display:flex; justify-content:flex-end; }
.isy-rel { background:var(--mud-palette-surface); border:1px solid var(--mud-palette-lines-default); border-radius:8px;
           padding:.6rem .75rem; display:flex; flex-direction:column; gap:.35rem; }
.isy-rel__top { display:flex; align-items:baseline; justify-content:space-between; gap:.6rem; }
.isy-rel__ed { font-weight:600; font-size:.9rem; line-height:1.45; }
.isy-rel__ed--none { font-weight:400; font-style:italic; color:var(--mud-palette-text-secondary); }
/* the counts never wrap: they are the reason to compare two cards */
.isy-rel__use { flex:0 0 auto; white-space:nowrap; font-size:.75rem; font-variant-numeric:tabular-nums; color:var(--mud-palette-text-secondary); }
.isy-rel__meta { display:flex; align-items:center; flex-wrap:wrap; gap:.5rem; font-size:.8rem; color:var(--mud-palette-text-secondary); }
/* pre-line keeps the change list a list; four lines is the most a card can hold before it stops being a card */
.isy-rel__notes { margin:0; font-size:.8rem; line-height:1.55; white-space:pre-line;
                  display:-webkit-box; -webkit-line-clamp:4; -webkit-box-orient:vertical; overflow:hidden; }
.isy-rel__notes--none { color:var(--mud-palette-text-secondary); font-style:italic; }
/* MudBlazor paints every body cell through ".mud-table-root .mud-table-body .mud-table-cell" — three
   classes, which outranked a bare ".isy-num--neg" sitting on the same td. Every money column in every
   MudTable rendered the same ink as the rest of the row, so overdue and credit had no signal at all.
   Matching that weight is the fix; !important would have won the same argument by shouting. */
.isy-num--neg, .mud-table-body .mud-table-cell.isy-num--neg { color: var(--mud-palette-error); font-weight: 600; }
.isy-num--pos, .mud-table-body .mud-table-cell.isy-num--pos { color: var(--mud-palette-success); font-weight: 600; }

/* Blazor's reconnect / error strip */
#blazor-error-ui { color-scheme: light only; background: lightyellow; bottom: 0; box-shadow: 0 -1px 2px rgba(0,0,0,.2); box-sizing: border-box; display: none; left: 0; padding: .6rem 1.25rem .7rem 1.25rem; position: fixed; width: 100%; z-index: 1000; }
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: .75rem; top: .5rem; }

:focus-visible { outline: 2px solid var(--isy-green); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }

/* horizontal top menu (replaces the side drawer) */
.isy-topnav { display: flex; align-items: center; gap: .15rem; height: 100%; flex: 0 0 auto; }
/* .main-nav on isystems.app: ink text, and the active item is green text over a green underline.
   Never a filled block — a fill in the bar would read as a button. */
.isy-topnav__link { position: relative; border-radius: 999px; padding-inline: .7rem; white-space: nowrap; flex: 0 0 auto; min-width: 0; color: var(--mud-palette-text-primary); }
.isy-topnav__link:hover { background: transparent; color: var(--isy-green-deep); }
.isy-topnav__link--active { color: var(--isy-green-deep); font-weight: 700; background: transparent; }
/* the underline is a pseudo-element, not a border-bottom: on a 999px radius a border curves round
   the ends and reads as a ring. The site draws a straight inset bar, so we do too. */
.isy-topnav__link--active::after { content: ""; position: absolute; inset-inline: .7rem; bottom: 4px;
                                   height: 2px; border-radius: 2px; background: var(--isy-green); }
/* «الإدارة»: a menu that looks like the links beside it, underlined when one of its pages is open. */
.isy-topnav__group { flex: 0 0 auto; }
.isy-topnav__group .mud-button-root { border-radius: 999px; padding-inline: .7rem; white-space: nowrap; color: var(--mud-palette-text-primary); text-transform: none; }
.isy-topnav__group .mud-button-root:hover { background: transparent; color: var(--isy-green-deep); }
.isy-topnav__group--active .mud-button-root { color: var(--isy-green-deep); font-weight: 700; position: relative; }
.isy-topnav__group--active .mud-button-root::after { content: ""; position: absolute; inset-inline: .7rem; bottom: 4px; height: 2px; border-radius: 2px; background: var(--isy-green); }
.isy-navmenu { display: none; }
.isy-brand, .isy-tagline { white-space: nowrap; flex: 0 0 auto; }
/* brand lock-up in the app bar: mark on a white chip, then the wordmark */
.isy-brand { display: flex; align-items: center; gap: .5rem; color: inherit; margin-inline: .25rem .75rem; }
.isy-brand__chip { display: inline-flex; }
.isy-brand__chip img { height: 22px; width: auto; display: block; }
.isy-brand__name { font-size: 1.05rem; font-weight: 700; color: var(--isy-navy); }
.isy-tagline { color: var(--mud-palette-text-secondary); margin-inline-end: 1.5rem; }

/* nothing in the bar squeezes or wraps. As the window narrows the bar gives up, in order:
   the tagline, then the link icons (the words stay - they are what people read), and last
   the whole row, which folds into the drop-down. --many is the back-office nav (7-8 links). */
@media (max-width: 1399px) { .isy-tagline { display: none; } }
@media (max-width: 1349px) {
    .isy-topnav--many .mud-button-icon-start { display: none; }
    .isy-topnav--many .isy-topnav__link { padding-inline: .45rem; font-size: .8125rem; }
}
@media (max-width: 1099px) {
    .isy-topnav .mud-button-icon-start { display: none; }
    .isy-topnav__link { padding-inline: .45rem; font-size: .8125rem; }
}
@media (max-width: 999px) {
    .isy-topnav { display: none; }
    /* The menu button goes FIRST — the start edge, before the mark — where a thumb expects it on a phone.
       It inherited the link row's slot, which put it mid-bar between the name and the bell (owner, 3 Nov 2026). */
    .isy-navmenu { display: inline-flex; order: -1; margin-inline: -8px 4px; }
}

/* company workspace */
.isy-ws-head { display:flex; flex-wrap:wrap; justify-content:space-between; align-items:flex-start; gap:.75rem 1.5rem; }
.isy-ws-actions { display:flex; align-items:center; flex-wrap:wrap; gap:.5rem; padding-top:.35rem; }
.isy-ws-tools { display:flex; align-items:center; gap:1rem; margin-top:.6rem; }
.isy-ws-switch { width:320px; max-width:100%; }
.isy-ws-switch .mud-input-control-input-container { margin-top:0; }
.isy-kpis { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:.6rem; }
.isy-kpi { padding:.6rem .8rem; display:flex; flex-direction:column; gap:.05rem; }
.isy-kpi__l { font-size:.7rem; letter-spacing:.08em; text-transform:uppercase; color:var(--mud-palette-text-secondary); }
[dir="rtl"] .isy-kpi__l { letter-spacing:0; font-size:.78rem; }
.isy-kpi__v { font-family:var(--isy-mono); font-size:1.35rem; font-weight:600; line-height:1.2; }
.isy-kpi__s { font-size:.78rem; color:var(--mud-palette-text-secondary); }
.isy-cards { display:grid; grid-template-columns:repeat(auto-fill,minmax(280px,1fr)); gap:.8rem; }
.isy-lic { padding:.8rem 1rem; display:flex; flex-direction:column; gap:.15rem; }
.isy-lic__actions { display:flex; gap:.4rem; margin-top:.5rem; }
.isy-perf { display:grid; grid-template-columns:1fr 1fr; gap:.6rem .8rem; }
.isy-perf div { display:flex; flex-direction:column; } .isy-perf b { font-size:1.15rem; }
.isy-spark { display:block; margin-top:.2rem; }
.isy-dl { display:grid; grid-template-columns:max-content 1fr; gap:.2rem 1rem; margin:.5rem 0; }
.isy-dl dt { color:var(--mud-palette-text-secondary); font-size:.85rem; } .isy-dl dd { margin:0; }

.isy-lic__actions { align-items:center; }
.isy-cards { align-items:stretch; }

/* global search in the app bar */
.isy-gsearch { flex:0 1 320px; min-width:180px; max-width:340px; margin-inline-end:.5rem; }
@media (max-width:1349px) { .isy-gsearch { flex-basis:230px; } }
.isy-gsearch .mud-input { color: var(--mud-palette-text-primary); }
.isy-gsearch .mud-input-outlined-border { border-color: var(--mud-palette-lines-default) !important; }
.isy-gsearch .mud-input-adornment, .isy-gsearch input::placeholder { color: var(--mud-palette-text-secondary); }
.isy-gsearch__kind { font-size:.7rem; letter-spacing:.06em; text-transform:uppercase; opacity:.6; margin-inline-end:.5rem; }

/* Tabs. The bar WRAPS when its tabs do not fit — it never scrolls. MudBlazor's scrolling tab bar
   translates the tabs by a measured offset, and in an RTL page that offset carries the wrong sign: the
   company page's eight tabs vanished behind two arrows on a 1000px window and on every phone (owner,
   3 Nov 2026). With the wrapper free to wrap there is nothing to scroll, so the arrows never appear;
   the library's slider is replaced by an underline on the active tab, because the slider is positioned
   by script along one line and lands under the wrong tab once there are two rows.
   (The class is .mud-tabs-tabbar in MudBlazor 9 — the old .mud-tabs-toolbar rule here matched nothing.) */
.isy-tabs .mud-tabs-tabbar { border-bottom:1px solid var(--mud-palette-lines-default); }
.isy-tabs .mud-tabs-tabbar-content { overflow: visible; white-space: normal; }
.isy-tabs .mud-tabs-tabbar-wrapper { width: 100%; flex-wrap: wrap; transform: none !important; }
.isy-tabs .mud-tabs-scroll-button, .isy-tabs .mud-tab-slider { display: none; }
.isy-tabs .mud-tab { width: auto; flex: 0 0 auto; text-transform: none; }
.isy-tabs .mud-tab.mud-tab-active { box-shadow: inset 0 -2px 0 var(--isy-green); }
.isy-tabs .mud-tabs-panels { padding-top:1.25rem; }
.isy-tabpanel { padding-top:.25rem; }
.isy-kpis { margin-top:.25rem; }

.isy-row--dim td { opacity:.55; }

.isy-drawer { padding:1rem 1.25rem; overflow-y:auto; height:100%; }

/* monospace for the typed value only — label and helper text keep the UI font and direction */
.isy-mono-input .mud-input-slot, .isy-mono-input input { font-family: var(--isy-mono); direction: ltr; unicode-bidi: isolate; text-align: start; }

/* unread counter in the app bar: MudBlazor hangs the badge over the button's corner, 8px
   above it, and the dense (48px) bar has no room - the top of the number was cut off by the
   window edge. Sit it on the bell's own corner instead, fully inside the bar. */
.isy-bell .mud-badge { inset: auto auto calc(100% - 23px) calc(100% - 28px) !important; }

/* user menu in the app bar */
.isy-usermenu { flex:0 0 auto; }
.isy-usermenu .mud-button-label { white-space:nowrap; }
.isy-usermenu__btn { text-transform:none; font-weight:500; padding-inline:.5rem; }
.isy-usermenu__signout { display:flex; align-items:center; width:100%; background:none; border:0; padding:.5rem 1rem; cursor:pointer; font:inherit; color:inherit; }
.isy-usermenu__signout:hover { background: var(--mud-palette-action-default-hover); }

.isy-lic--link { cursor:pointer; transition:box-shadow .15s; } .isy-lic--link:hover { box-shadow: var(--mud-elevation-4); }

/* customer dashboard */
.isy-kpis--compact .isy-kpi__v { font-size:1.2rem; }
.isy-attention { display:flex; flex-direction:column; gap:.4rem; }
.isy-attention__item { display:flex; align-items:center; gap:.6rem; padding:.5rem .8rem; background:var(--mud-palette-surface); border:1px solid var(--mud-palette-lines-default); border-inline-start-width:4px; border-radius:6px; color:inherit; text-decoration:none; }
.isy-attention__item:hover { box-shadow: var(--mud-elevation-2); }
.isy-attention__title { font-weight:600; }
.isy-attention__detail { color:var(--mud-palette-text-secondary); font-size:.85rem; flex-grow:1; }
.isy-attention__go { opacity:.5; }
[dir="ltr"] .isy-attention__go { transform: scaleX(-1); }
.isy-cards--2 { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.isy-product { min-height: 190px; }
/* The action row belongs at the foot of the card, not wherever the text above it happened to stop: one card
   with a two-line edition and its neighbour with none put "فتح" at different heights across the row. The grid
   already stretches the cards to equal height, which is what gives "auto" free space to take. Padding, not
   margin, keeps the gap: auto collapses to 0 on a card whose content fills the height. */
.isy-product .isy-lic__actions { margin-block-start:auto; padding-block-start:.5rem; }
/* The name always takes two lines, clamped, so the facts under it start at one height across a row: a
   three-line name pushed its card's version lower than its neighbour's. Icon, tag and pin sit on the
   name's first line, not on the middle of the block. */
.isy-product__head { display:flex; align-items:flex-start; gap:.5rem; }
.isy-product__icon { opacity:.6; margin-block-start:.15rem; flex-shrink:0; }
.isy-product__name { flex:1; min-width:0; font-weight:600; font-size:1rem; line-height:1.5; min-height:3em;
  overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; }
.isy-product__end { display:flex; align-items:center; gap:.15rem; flex-shrink:0; margin-block-start:-.2rem; }
.isy-product__facts { display:grid; grid-template-columns: 1fr 1fr; gap:.35rem .8rem; margin:.4rem 0 .2rem; }
.isy-product__facts > div { display:flex; flex-direction:column; }
.isy-timeline { display:flex; flex-direction:column; gap:.4rem; }
.isy-timeline__item { display:block; padding:.55rem .8rem; background:var(--mud-palette-surface); border:1px solid var(--mud-palette-lines-default); border-radius:6px; color:inherit; text-decoration:none; }
.isy-timeline__item:hover { box-shadow: var(--mud-elevation-2); }
.isy-timeline__head { display:flex; align-items:center; gap:.5rem; }
.isy-timeline__ver { font-weight:600; }
.isy-timeline__date { color:var(--mud-palette-text-secondary); font-size:.8rem; }
.isy-timeline__products { font-size:.85rem; color:var(--mud-palette-text-secondary); }
.isy-timeline__note { font-size:.9rem; margin-top:.2rem; overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; text-align:start; }

/* back-office dashboard */
.isy-kpi--link { cursor:pointer; transition:box-shadow .15s; }
.isy-kpi--link:hover { box-shadow: var(--mud-elevation-4); }
.isy-attention__val { font-family:var(--isy-mono); font-size:1.2rem; font-weight:600; min-width:2.6rem; text-align:center; }
.isy-collect { display:grid; grid-template-columns:max-content 1fr max-content; gap:.7rem 1rem; align-items:center; }
.isy-collect .isy-num b { font-size:1.05rem; }
.isy-actv { display:flex; align-items:baseline; gap:.5rem 1rem; flex-wrap:wrap; padding:.45rem .25rem; }
.isy-actv + .isy-actv { border-top:1px solid var(--mud-palette-lines-default); }
.isy-actv__sol { min-width:160px; }
.isy-actv__list { display:flex; flex-wrap:wrap; gap:.25rem; }
@media (max-width:700px) { .isy-roll, .isy-collect { grid-template-columns:1fr; gap:.25rem; } }

/* news feed */
.isy-feed__title { font-weight:500; }
.isy-feed--unread { border-inline-start:3px solid var(--mud-palette-primary); }
.isy-feed--unread .isy-feed__title { font-weight:700; }
.isy-feed--pinned { background: var(--isy-cream); }

/* customer usage rows (home) */
.isy-kpi__v--text { font-family: inherit; letter-spacing: 0; }
.isy-usage { display:flex; flex-direction:column; gap:.4rem; }
.isy-usage__row { display:grid; grid-template-columns: minmax(200px, 2fr) 1fr 1fr 1fr auto; gap:.6rem; align-items:center; padding:.55rem .8rem; background:var(--mud-palette-surface); border:1px solid var(--mud-palette-lines-default); border-inline-start-width:4px; border-radius:6px; color:inherit; text-decoration:none; }
.isy-usage__row:hover { box-shadow: var(--mud-elevation-2); }
.isy-usage__name { display:flex; align-items:center; gap:.5rem; font-weight:600; min-width:0; }
.isy-usage__name > span:first-of-type { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.isy-usage__cell { display:flex; flex-direction:column; }
@media (max-width: 800px) { .isy-usage__row { grid-template-columns: 1fr 1fr; } .isy-usage__name { grid-column: 1 / -1; } }
/* feed */
.isy-feed--link { cursor:pointer; }
.isy-feed--link:hover { box-shadow: var(--mud-elevation-2); }
.isy-timeline__item:not(.isy-feed--link):hover { box-shadow:none; }
/* stepped form */
.isy-form { display:flex; flex-direction:column; gap:1.1rem; }
.isy-form__sec { padding:.6rem .9rem .9rem; border:1px solid var(--mud-palette-lines-default); border-radius:8px; }
.isy-form__h { display:flex; align-items:center; gap:.6rem; font-weight:600; margin-bottom:.3rem; }
.isy-form__n { display:inline-flex; width:1.4rem; height:1.4rem; border-radius:50%; background:var(--mud-palette-primary); color:#fff; align-items:center; justify-content:center; font-size:.8rem; font-family:var(--isy-mono); }
.isy-form__hint { font-weight:400; font-size:.8rem; color:var(--mud-palette-text-secondary); }

/* customer home v3: news hero + right rail */
.isy-sec__h { display:flex; align-items:center; gap:.5rem; margin-bottom:.6rem; }
.isy-sec__h .mud-icon-root { opacity:.7; }
.isy-rail { display:flex; flex-direction:column; gap:1rem; }
.isy-rail__card { padding:.8rem 1rem 1rem; }
.isy-quick { display:grid; grid-template-columns:1fr 1fr; gap:.5rem; }
.isy-quick__i { display:flex; flex-direction:column; padding:.5rem .7rem; border:1px solid var(--mud-palette-lines-default); border-radius:6px; color:inherit; text-decoration:none; }
.isy-quick__i[href]:hover { box-shadow: var(--mud-elevation-2); }
.isy-quick .isy-kpi__v { font-size:1.15rem; }
.isy-bars { display:flex; align-items:flex-end; gap:4px; height:110px; padding-top:1rem; }
.isy-bars__col { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:flex-end; height:100%; min-width:0; position:relative; }
.isy-bars__bar { width:100%; max-width:22px; background:var(--mud-palette-primary); opacity:.55; border-radius:3px 3px 0 0; }
.isy-bars__bar--now { opacity:1; }
.isy-bars__n { font-family:var(--isy-mono); font-size:.65rem; color:var(--mud-palette-text-secondary); line-height:1; height:.8rem; }
.isy-bars__l { font-size:.6rem; color:var(--mud-palette-text-secondary); margin-top:.2rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%; }
.isy-acts { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:.35rem; }
.isy-acts__i { display:flex; align-items:center; gap:.5rem; font-size:.9rem; }
.isy-acts__ic { opacity:.6; }
.isy-acts__t { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.isy-acts__d { font-size:.75rem; color:var(--mud-palette-text-secondary); }
.isy-attention__action { font-size:.8rem; font-weight:600; color:var(--mud-palette-primary); }

/* customer home v4: status strip, update banner, product list, feed tags (29 Aug 2026) */
.isy-status { display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:.75rem; }
.isy-status--2 { grid-template-columns:repeat(2, minmax(0,1fr)); }
@media (max-width: 800px) { .isy-status, .isy-status--2 { grid-template-columns:1fr; } }
.isy-status__i { display:flex; align-items:center; gap:.8rem; padding:.75rem .9rem; border:1px solid var(--mud-palette-lines-default); border-radius:8px; background:var(--mud-palette-surface); color:inherit; text-decoration:none; }
.isy-status__i:hover { box-shadow: var(--mud-elevation-2); }
.isy-status__ic { display:inline-flex; align-items:center; justify-content:center; width:2.4rem; height:2.4rem; border-radius:8px; flex-shrink:0; }
.isy-status__t { display:flex; flex-direction:column; gap:.05rem; min-width:0; }
.isy-status__l { font-size:.75rem; color:var(--mud-palette-text-secondary); }
.isy-status__v { font-size:1.05rem; font-weight:700; line-height:1.3; }
.isy-status__s { font-size:.75rem; color:var(--mud-palette-text-secondary); }
.isy-status--ok .isy-status__ic { background: color-mix(in srgb, var(--mud-palette-success) 14%, transparent); color: var(--mud-palette-success); }
.isy-status--ok .isy-status__v { color: var(--mud-palette-success); }
.isy-status--warn { background: color-mix(in srgb, var(--mud-palette-warning) 8%, var(--mud-palette-surface)); border-color: color-mix(in srgb, var(--mud-palette-warning) 45%, transparent); }
.isy-status--warn .isy-status__ic { background: color-mix(in srgb, var(--mud-palette-warning) 22%, transparent); color: var(--mud-palette-warning-darken); }
.isy-status--warn .isy-status__v { color: var(--mud-palette-warning-darken); }
.isy-status--bad { background: color-mix(in srgb, var(--mud-palette-error) 7%, var(--mud-palette-surface)); border-color: color-mix(in srgb, var(--mud-palette-error) 45%, transparent); }
.isy-status--bad .isy-status__ic { background: color-mix(in srgb, var(--mud-palette-error) 16%, transparent); color: var(--mud-palette-error); }
.isy-status--bad .isy-status__v { color: var(--mud-palette-error); }

.isy-update { display:flex; align-items:center; gap:1rem; padding:.9rem 1.1rem; background:var(--mud-palette-surface); border:1px solid var(--mud-palette-lines-default); border-inline-start:4px solid var(--mud-palette-warning); border-radius:8px; }
.isy-update__ic { display:inline-flex; align-items:center; justify-content:center; width:2.6rem; height:2.6rem; border-radius:8px; background:var(--isy-ground); flex-shrink:0; }
.isy-update__t { display:flex; flex-direction:column; gap:.15rem; flex-grow:1; min-width:0; }
.isy-update__title { font-weight:700; font-size:1.05rem; }
.isy-update__meta { display:flex; flex-wrap:wrap; align-items:center; gap:.4rem; font-size:.85rem; color:var(--mud-palette-text-secondary); }
.isy-update__new { font-weight:700; color:var(--mud-palette-text-primary); }
.isy-update__sep { opacity:.5; }
.isy-update__a { display:flex; align-items:center; gap:.5rem; flex-shrink:0; }
@media (max-width: 800px) { .isy-update { flex-wrap:wrap; } .isy-update__a { width:100%; justify-content:flex-end; } }

.isy-prods { display:flex; flex-direction:column; gap:.5rem; }
.isy-prods__i { display:flex; align-items:center; justify-content:space-between; gap:.6rem; padding:.55rem .75rem; border:1px solid var(--mud-palette-lines-default); border-radius:8px; color:inherit; text-decoration:none; }
.isy-prods__i:hover { box-shadow: var(--mud-elevation-2); }
.isy-prods__i--behind { background: color-mix(in srgb, var(--mud-palette-warning) 8%, var(--mud-palette-surface)); border-color: color-mix(in srgb, var(--mud-palette-warning) 45%, transparent); }
.isy-prods__t { display:flex; flex-direction:column; min-width:0; }
.isy-prods__n { font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.isy-prods__v { font-size:.75rem; color:var(--mud-palette-text-secondary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

.isy-tag { display:inline-flex; align-items:center; padding:.1rem .5rem; border-radius:4px; font-size:.7rem; font-weight:700; white-space:nowrap; line-height:1.5; }
.isy-tag--ok { background: color-mix(in srgb, var(--mud-palette-success) 14%, transparent); color: var(--mud-palette-success); }
.isy-tag--warn { background: var(--mud-palette-warning); color:#fff; }


.isy-tag--pin { background: var(--mud-palette-dark); color: var(--mud-palette-dark-text); }
.isy-tag--prog { background: color-mix(in srgb, var(--mud-palette-primary) 10%, transparent); color: var(--mud-palette-primary); }

.isy-feed__filters { display:flex; justify-content:flex-end; margin-bottom:.5rem; }
.isy-feed__more { display:flex; justify-content:center; padding:.4rem 0 0; }
.isy-tag--new { background: var(--mud-palette-info); color:#fff; }
.isy-feed--new { border-color: color-mix(in srgb, var(--mud-palette-info) 55%, transparent); }

/* my products v2: pool summary + one block per program with a licence table (30 Aug 2026) */
.isy-pools { display:flex; flex-direction:column; gap:.6rem; }
.isy-pool { padding:.7rem 1rem .8rem; display:flex; flex-direction:column; gap:.5rem; }
.isy-pool__h { display:flex; align-items:center; gap:.6rem; flex-wrap:wrap; }
.isy-pool__n { font-weight:600; }
.isy-pool__s { font-size:.8rem; color:var(--mud-palette-text-secondary); }
.isy-pool__v { font-size:.95rem; }
.isy-prog { padding:0; overflow:hidden; }
.isy-prog__h { display:flex; align-items:center; gap:.6rem; flex-wrap:wrap; padding:.8rem 1rem; border-bottom:1px solid var(--mud-palette-lines-default); }
.isy-prog__rel { font-size:.85rem; color:var(--mud-palette-text-secondary); }
.isy-table { width:100%; border-collapse:collapse; font-size:.9rem; }
.isy-table th { text-align:start; font-weight:500; font-size:.75rem; color:var(--mud-palette-text-secondary); padding:.5rem 1rem; border-bottom:1px solid var(--mud-palette-lines-default); white-space:nowrap; }
.isy-table td { padding:.55rem 1rem; border-bottom:1px solid var(--mud-palette-lines-default); vertical-align:middle; }
.isy-table tr:last-child td { border-bottom:none; }
.isy-table__row { cursor:pointer; }
.isy-table__row:hover td { background: color-mix(in srgb, var(--mud-palette-primary) 5%, transparent); }
.isy-table__note { max-width:260px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:.85rem; }
.isy-table__go { width:2.5rem; text-align:end; }
@media (max-width: 800px) { .isy-table th:nth-child(3), .isy-table td:nth-child(3), .isy-table__note { display:none; } }

/* my products v3: devices hero (30 Aug 2026) */
.isy-devices { display:flex; align-items:center; gap:1.5rem; padding:1rem 1.25rem; border-inline-start:4px solid var(--mud-palette-primary); }
.isy-devices--low { border-inline-start-color: var(--mud-palette-warning); }
.isy-devices--full { border-inline-start-color: var(--mud-palette-error); }
.isy-devices__t { display:flex; flex-direction:column; gap:.1rem; flex-grow:1; min-width:0; }
.isy-devices__l { font-size:.8rem; color:var(--mud-palette-text-secondary); }
.isy-devices__v { font-size:1.6rem; font-weight:700; line-height:1.2; }
.isy-devices--low .isy-devices__v { color: var(--mud-palette-warning-darken); }
.isy-devices--full .isy-devices__v { color: var(--mud-palette-error); }
.isy-devices__s { font-size:.85rem; color:var(--mud-palette-text-secondary); }
.isy-devices__a { display:flex; flex-direction:column; align-items:flex-end; gap:.4rem; flex-shrink:0; }
.isy-devices__hint { font-size:.8rem; color:var(--mud-palette-text-secondary); }
@media (max-width: 800px) { .isy-devices { flex-wrap:wrap; } .isy-devices__a { width:100%; align-items:stretch; } }
.isy-product__descr { margin-top:.15rem; overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; }

/* ---- statement: what was bought, what was paid, and the action to record one -------------------
   These three used to run together on one line, with the payment box (which defaults to the full
   open amount) printing the same number as the charge total right beside it. Separated on purpose. */
.isy-ledger { display: flex; gap: 0 18px; flex-wrap: wrap; align-items: flex-end; }
.isy-ledger > div { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.25; }
.isy-ledger span { font-size: .72rem; color: var(--mud-palette-text-secondary); white-space: nowrap; }
.isy-ledger b { font-family: var(--isy-mono, ui-monospace, Consolas, monospace); font-variant-numeric: tabular-nums; font-weight: 500; }
.isy-ledger__total b { font-weight: 700; font-size: 1.05rem; }
.isy-ledger--head { gap: 0 22px; }

.isy-paid { display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap; margin-top: .5rem;
            padding-top: .5rem; border-top: 1px dashed var(--mud-palette-lines-default); font-size: .82rem; }
.isy-paid__l, .isy-payin__l { font-size: .72rem; letter-spacing: .04em; color: var(--mud-palette-text-secondary); }
/* the action's heading sits ABOVE its controls, not beside the amount field's floating label */
.isy-payin__l { flex-basis: 100%; margin-bottom: -2px; }
.isy-paid__row { display: inline-flex; align-items: baseline; gap: 8px;
                 background: var(--mud-palette-background-grey); border-radius: 12px; padding: 2px 10px; }
.isy-paid__row--adj { opacity: .8; font-style: italic; }

.isy-payin { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: .5rem;
             padding-top: .5rem; border-top: 1px dashed var(--mud-palette-lines-default); }

/* Never put a width in Style= on a MudDatePicker. MudBlazor copies that Style onto the calendar
   POPUP as well as onto the input, so Style="max-width:160px" shrank the calendar itself to 160px:
   the month title read "ber 2026", three weekday columns were cut away, and in Arabic the clipped
   half fell off the LEFT edge. Size this wrapper instead — the popup is drawn at the document root
   by MudPopoverProvider, so a rule under a wrapper can never reach it. */
.isy-datefield { min-width: 140px; max-width: 160px; }

/* ---- charge card: the facts under the title ---------------------------------------------------
   These used to be one dot-separated run — date · due · qty · period · description — which is a wall
   of text at a glance. Each fact now carries its own label and can be found by scanning. */
.isy-facts { display: flex; flex-wrap: wrap; gap: 3px 18px; margin-top: .35rem; font-size: .82rem; }
.isy-facts > span { display: inline-flex; align-items: baseline; gap: 6px; }
.isy-facts i { font-style: normal; font-size: .72rem; color: var(--mud-palette-text-secondary); }
.isy-facts b { font-weight: 500; font-variant-numeric: tabular-nums; }

/* The description is the human content of a customisation or a service — give it a line of its own. */
.isy-note { margin-top: .45rem; padding-inline-start: 9px; font-size: .86rem;
            border-inline-start: 2px solid color-mix(in srgb, var(--mud-palette-primary) 45%, transparent);
            color: var(--mud-palette-text-primary); }

/* ---- activity feed ----------------------------------------------------------------------------
   Was a paragraph of stored English wrapped around Arabic names and Latin ids. Now a fixed grid:
   date, what happened, the detail, how many times, who. */
.isy-act { display: grid; grid-template-columns: auto auto 1fr auto auto; align-items: center;
           gap: 0 8px; padding: 3px 0; font-size: .84rem; line-height: 1.45; }
.isy-act + .isy-act { border-top: 1px solid var(--mud-palette-lines-default); }
.isy-act__d { color: var(--mud-palette-text-secondary); white-space: nowrap; font-size: .78rem; }
.isy-act__c { margin: 0; justify-self: start; }
.isy-act__t { min-width: 0; overflow-wrap: anywhere; }
.isy-act__n { font-family: var(--isy-mono, ui-monospace, Consolas, monospace); font-size: .75rem;
              background: var(--mud-palette-background-grey); border-radius: 10px; padding: 0 7px;
              white-space: nowrap; }
.isy-act__a { color: var(--mud-palette-text-secondary); font-size: .78rem; white-space: nowrap; }
/* One grid for the whole list, every row a subgrid of it (owner, 1 Nov 2026): a grid PER row sized its
   columns to that row alone, so dates, chips and names wandered from line to line. Every row emits all
   five cells, empty ones included, or the cells after a gap slide one column over. */
.isy-actgrid { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto auto; }
.isy-actgrid > .isy-act { grid-column: 1 / -1; grid-template-columns: subgrid; padding-inline: 6px; border-radius: 4px; }
.isy-act--link { cursor: pointer; }
.isy-act--link:hover { background: var(--mud-palette-action-default-hover); }
/* A phone: three lines. The chip at the start and the date at the end of the first, the detail on the
   second, the count and the actor on the third. Left to auto-placement the date — a block with its own
   ltr direction — sat alone on a line at the far edge, away from the chip it belongs with. */
@media (max-width: 700px) {
  .isy-actgrid { display: block; }
  .isy-act, .isy-actgrid > .isy-act { grid-template-columns: auto 1fr; row-gap: 2px; padding-block: 6px; }
  .isy-act__c { grid-row: 1; grid-column: 1; }
  .isy-act__d { grid-row: 1; grid-column: 2; justify-self: end; }
  .isy-act__t { grid-row: 2; grid-column: 1 / -1; }
  .isy-act > :nth-child(4) { grid-row: 3; grid-column: 1; }
  .isy-act__a { grid-row: 3; grid-column: 2; justify-self: end; }
}

/* The correct/remove buttons sit inside the payment pill, quiet until the row is hovered. */
.isy-paid__b { padding: 0 !important; width: 22px; height: 22px; opacity: .45; }
.isy-paid__row:hover .isy-paid__b, .isy-paid__b:focus-visible { opacity: 1; }

/* Rollout: one line per program. A per-product table filled half the dashboard with ten rows of one or
   two machines, because the products are SoftwareId variants of the same program. */
/* One grid, rows as subgrids: each figure sits under the same figure of the row above. */
.isy-rollout { display: grid; grid-template-columns: minmax(5rem, auto) auto auto 1fr; column-gap: 24px; row-gap: .35rem; }
.isy-rollout__row { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: baseline; font-size: .9rem; }
.isy-rollout__n { font-weight: 600; font-variant-numeric: tabular-nums; }

/* One attention card should not stretch the full width as if it were a banner. */
.isy-attention__item { max-width: 640px; }

/* ---- performance page ---------------------------------------------------------------------------
   isy-hbar, NOT isy-bars: that name is already the vertical column chart on the customer home, and
   reusing it silently restyled its labels and forced this grid to its 110px height. ---------------------------------------------------------------------------
   Bars in CSS, not a chart library: one scale, a direct label on every row, and no doubt about which
   way it renders in RTL. The collected part sits INSIDE the invoiced bar — same axis, never two. */
.isy-hbar { display: grid; grid-template-columns: minmax(0, 9rem) minmax(2rem, 1fr) minmax(0, max-content);
             gap: 6px 12px; align-items: center; }
/* Every column can shrink. Without minmax(0, ...) a max-content column grows past the panel and the
   bars spill over whatever sits beside them in the grid. */
.isy-hbar__l { font-size: .85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.isy-hbar__t { position: relative; height: 14px; min-width: 0; background: var(--mud-palette-background-grey); border-radius: 7px; overflow: hidden; }
.isy-hbar__b { position: absolute; inset-inline-start: 0; top: 0; height: 100%; border-radius: 7px;
               background: var(--mud-palette-lines-default); }
.isy-hbar__b--in { background: var(--mud-palette-primary); }
.isy-hbar__v { font-size: .82rem; font-variant-numeric: tabular-nums; white-space: nowrap; min-width: 0; }

/* Age and silence both get worse the further down the ladder you read, so the bar carries the severity.
   Colour is the SECOND signal here, never the only one: the label already names the band. */
.isy-hbar__b--warn { background: var(--mud-palette-warning); }
.isy-hbar__b--bad  { background: var(--mud-palette-error); }

/* The year trend is background, not a decision — it sits in a half-width panel, so its label column
   shrinks to what a four-digit year actually needs. */
.isy-hbar--tight { grid-template-columns: minmax(0, 3rem) minmax(2rem, 1fr) minmax(0, max-content); gap: 5px 10px; }

/* A panel is a box: nothing inside it may paint over its neighbour. */
.isy-panel { min-width: 0; overflow: hidden; }
/* Insights: every card fills its grid cell, so the two cards of a row end on the same line. */
.isy-ins-cell { display: flex; flex-direction: column; }
.isy-ins-cell > .isy-panel { flex: 1 1 auto; }
/* On a phone a table keeps its columns and scrolls sideways inside the card; the card hides overflow, so
   without this the money columns were simply cut off, and the names wrapped a word per line. */
@media (max-width: 700px) {
  .isy-ins-cell .mud-table-container { overflow-x: auto; }
  .isy-months__m { font-size: .6rem; }
}
/* A label that needs its whole name: two lines, wider column, nothing cut. */
.isy-hbar--wide { grid-template-columns: minmax(0, 15rem) minmax(2rem, 1fr) minmax(0, max-content); row-gap: 10px; }
.isy-hbar__l--two { display: flex; flex-direction: column; white-space: normal; line-height: 1.3; }
.isy-hbar__l--two > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.isy-hbar__l--two > span { font-size: .75rem; }
.isy-panel .mud-typography-caption { overflow-wrap: anywhere; }

/* Months read as columns, because a year is a shape before it is a list of numbers. */
.isy-months { display: flex; align-items: flex-end; gap: 8px; height: 150px; }
.isy-months__col { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; flex: 1; height: 100%; gap: 3px; }
.isy-months__n { font-size: .72rem; color: var(--mud-palette-text-secondary); }
.isy-months__bar { width: 100%; max-width: 34px; background: var(--mud-palette-primary); border-radius: 4px 4px 0 0; }
.isy-months__m { font-size: .72rem; color: var(--mud-palette-text-secondary); white-space: nowrap; }
.isy-months__y { font-size: .68rem; color: var(--mud-palette-text-secondary); min-height: 1em; }

.isy-row--link { cursor: pointer; }
.isy-row--link:hover { background: var(--mud-palette-action-default-hover); }

/* ---- programs list ------------------------------------------------------------------------------
   A card is a link, so the whole card is the hit area: the name carries the href and stretches an
   invisible overlay across the card. That keeps one anchor (focusable, middle-clickable, announced
   as a link) instead of a div with a click handler, and it leaves room for the edit button, which
   sits ABOVE the overlay rather than nested inside the anchor. */
.isy-prog { position: relative; padding: .8rem 1rem; display: flex; flex-direction: column; gap: .3rem;
            border-inline-start: 4px solid var(--mud-palette-primary); transition: box-shadow .15s; }
.isy-prog:hover { box-shadow: var(--mud-elevation-4); }
.isy-prog--off { border-inline-start-color: var(--mud-palette-lines-default); opacity: .62; }

.isy-prog__h { display: flex; align-items: center; gap: .5rem; padding-inline-end: 2rem; }
.isy-prog__link { font-weight: 600; font-size: 1rem; color: inherit; text-decoration: none; min-width: 0; overflow-wrap: anywhere; }
.isy-prog__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.isy-prog:hover .isy-prog__link { text-decoration: underline; }
.isy-prog__edit { position: absolute; inset-inline-end: .3rem; top: .3rem; z-index: 1; opacity: .35; }
.isy-prog:hover .isy-prog__edit, .isy-prog__edit:focus-visible { opacity: 1; }

/* Two lines of description, always the same height, so the version line of every card sits on one row. */
.isy-prog__d { font-size: .85rem; color: var(--mud-palette-text-secondary); min-height: 2.4em;
               overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }

/* When it last shipped. The version alone said nothing about whether the program is still alive. */
.isy-prog__ver { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-top: .2rem; }
.isy-prog__v { font-size: .95rem; font-weight: 600; }
.isy-prog__when { font-size: .8rem; color: var(--mud-palette-text-secondary); font-variant-numeric: tabular-nums; }

.isy-prog__facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: .2rem .6rem; margin-top: .5rem;
                   padding-top: .5rem; border-top: 1px solid var(--mud-palette-lines-default); }
.isy-prog__facts > div { display: flex; flex-direction: column; min-width: 0; }
.isy-prog__facts b { font-family: var(--isy-mono); font-size: 1.05rem; font-weight: 600; line-height: 1.2; }
.isy-prog__facts span { font-size: .7rem; letter-spacing: .04em; color: var(--mud-palette-text-secondary);
                        overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The licensing identity under the company name: "تحت ترخيص: المتحدة · k 01". A flex row so each run keeps
   its own bidi isolate and the separators do not collapse into the neighbouring Latin text. */
.isy-licensee-line { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem; margin-top: .15rem; }
.isy-licensee-line .isy-mono { font-family: var(--isy-mono); font-size: .78rem; opacity: .8; }

/* The search sits on the toolbar line with the totals; it must not stretch to fill the row. */
.isy-prog__search { max-width: 280px; }
@media (max-width: 600px) { .isy-prog__search { max-width: 100%; } }

/* Table toolbar filters.
   Two MudBlazor facts bite here. First, a labelled input gets 16px reserved above it
   for the floating label and an unlabelled one does not, so a placeholder-only search
   sits ~8px higher than the select beside it; --nolabel gives back the same reserve.
   Second, the mr-* utilities are physical margins that do not flip, so in Arabic the
   gap landed outside the row instead of between the two controls — hence inline-end. */
.isy-tbfield { margin-inline-end: 16px; }
.isy-tbfield--nolabel { margin-top: 16px; }

/* Users toolbar. Two things to know.
   1. The row aligns on the bottom of the inputs (align-end), not on their centres: the search
      carries no floating label and the two selects do, so centring puts the search line ~8px
      above the selects. Bottom alignment holds in both languages with no margin hack (the old
      one was a top margin that mt-0 cancelled anyway, being !important).
   2. MudSelect puts its Class on the inner .mud-input-control, NOT on the outer .mud-select
      wrapper that is the flex child — so a width set through Class never reaches the box that
      is being laid out, and the selects stretch across the row. Size the wrapper from here. */
.isy-users__search { flex: 0 1 280px; max-width: 280px; }
.isy-users__toolbar > .mud-select { flex: 0 0 190px; }
@media (max-width: 600px) {
  .isy-users__search, .isy-users__toolbar > .mud-select { flex-basis: 100%; max-width: 100%; }
}

/* Every table toolbar is free to grow. .mud-toolbar is a hard 56px, so once a search, a picker and a
   button wrap on a narrow screen they stand three rows tall inside a one-row box and paint over the
   first rows of the table (the Companies page on a phone, 3 Nov 2026 — the money page had the same
   fault first and carried this rule alone through :has(); MudTable has no parameter that puts a class
   on its toolbar, ToolBarClass is silently dropped). The rows that wrap get a gap of their own. */
.mud-table-toolbar { height: auto; min-height: 56px; padding-block: 8px; flex-wrap: wrap; row-gap: 8px; }
/* Money page toolbar. Two things, both measured on the page rather than guessed.
   1. Same MudSelect fact as the Users bar above: its Class and Style land on the inner
      .mud-input-control and never on the .mud-select flex child, so both boxes are sized from here.
      Without the group taking the free width, the four controls needed 799px, got 789px, and the
      last switch dropped to a second line.
   2. The switches carry NO margin. On a bottom-aligned row MudBlazor already lands the switch centre
      within half a pixel of the input text line; any nudge here only pushes it back out. */
.isy-money__tb { flex: 1 1 auto; min-width: 0; }
/* The licence lines under an expanded money row: on a phone the cell is a flex line, so the block must
   claim the whole line and scroll sideways rather than shrink to a column of digits. */
.isy-money__lines { flex: 1 1 100%; min-width: 0; overflow-x: auto; }
.isy-money__search { flex: 0 1 320px; max-width: 320px; }
.isy-money__tb > .mud-select { flex: 0 0 190px; }
.isy-money__tb .isy-money__sw { margin: 0; }
@media (max-width: 600px) {
  .isy-money__search, .isy-money__tb > .mud-select { flex-basis: 100%; max-width: 100%; }
}

/* Users, grouped by company. Two table cells: the company on one side, its accounts stacked on the other.
   The accounts are a CSS grid and not a nested table, for one reason that matters: a grid keeps the
   columns of every account line aligned WITHIN its company, while the browser is still free to size the
   two outer cells — a nested table would set its own widths per company and nothing would line up down
   the page. Physical left/right never appears here; the page runs right-to-left in Arabic. */
.isy-ugrp .isy-ugrp__co { width: 28%; vertical-align: top; padding-top: 12px; }
.isy-ugrp__coname { font-weight: 600; line-height: 1.35; }
.isy-ugrp__cometa { display: flex; align-items: center; gap: 8px; margin-top: 2px; font-size: .78rem; color: var(--mud-palette-text-secondary); }
.isy-ugrp .isy-ugrp__users { padding-block: 4px; }
.isy-ugrp__count { white-space: nowrap; }

/* One account. The last three tracks are fixed so the level, the last sign-in and the two little
   controls stand in a column instead of drifting with the length of each name. */
.isy-ugrp__u {
  display: grid; align-items: center; gap: 4px 12px;
  grid-template-columns: minmax(0, 1fr) 150px 110px 24px 36px;
  padding-block: 6px;
}
.isy-ugrp__u + .isy-ugrp__u { border-top: 1px solid var(--mud-palette-table-lines); }
.isy-ugrp__who { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; min-width: 0; }
.isy-ugrp__name { font-weight: 500; }
/* The record number and the mail address are for the rare moment somebody needs them, not for scanning. */
.isy-ugrp__id, .isy-ugrp__mail { font-size: .75rem; color: var(--mud-palette-text-secondary); }
.isy-ugrp__mail { overflow-wrap: anywhere; }
.isy-ugrp__lvl, .isy-ugrp__seen { font-size: .8rem; color: var(--mud-palette-text-secondary); }
/* CompanyAdminWithReportCertificates is a real level name and it is longer than its track, so without
   this it printed straight over the sign-in date beside it. It wraps rather than being clipped: an
   ellipsis on a Latin word inside a right-to-left page eats the START of it ("...ithReportCertificates"),
   which is the half that tells the two Company* levels apart. */
.isy-ugrp__lvl { min-width: 0; overflow-wrap: anywhere; line-height: 1.3; }

/* Narrow screens: MudBlazor turns the table into stacked cards, so each account becomes two lines — who,
   then everything about them. The grid is dropped here, not just re-tracked: inside a phone-width cell a
   1fr track collapses to its minimum, and with overflow-wrap:anywhere that minimum is ONE CHARACTER, so
   "CompanyAdmin" came out spelled downwards. Flex lets the same items wrap on their own. */
@media (max-width: 960px) {
  .isy-ugrp .isy-ugrp__co { width: auto; }
  .isy-ugrp__u { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
  .isy-ugrp__who { flex: 1 1 100%; }
  .isy-ugrp__lvl { overflow-wrap: normal; }
}

/* ---- dashboard: the money line, twelve months ----------------------------------------------------
   isy-mbar, NOT isy-bars: that name is the customer home's plain column chart, which carries one series.

   Two bars per month, side by side on ONE scale — not one nested inside the other. Nesting is how the
   performance page draws a product's charged-vs-collected, and it is right there because those payments
   settle that product's own charges. Money received in a MONTH is not a part of what that month invoiced:
   a payment in May settles a charge from January. Drawn nested, every column filled to 100% and the chart
   said nothing. Navy against brass, never a second axis. */
.isy-mbar { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 6px; align-items: end; height: 132px; }
.isy-mbar__col { display: flex; flex-direction: column; justify-content: flex-end; align-items: center;
                 height: 100%; min-width: 0; gap: 3px; }
/* 2px between the pair: touching fills read as one mark. */
.isy-mbar__pair { position: relative; display: flex; align-items: flex-end; justify-content: center; gap: 2px; width: 100%; height: 100%; }
/* No min-height: a month that invoiced nothing must draw nothing. The 2% floor in Height() keeps a small
   month visible; a zero month is left empty, which is the true answer. */
.isy-mbar__b { width: 40%; max-width: 11px; border-radius: 3px 3px 0 0; }
.isy-mbar__b--out { background: var(--mud-palette-dark); }
.isy-mbar__b--in { background: var(--mud-palette-primary); }
.isy-mbar__l { font-size: .62rem; color: var(--mud-palette-text-secondary); white-space: nowrap;
               overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.isy-mbar__col--now .isy-mbar__l { color: var(--mud-palette-text-primary); font-weight: 600; }
/* Only the current month carries a printed number. A value on all twelve is noise, not a label. It is
   pinned just above that month's taller bar — parked at the top of the panel it read as a stray figure. */
.isy-mbar__v { position: absolute; inset-inline: -50%; text-align: center; font-family: var(--isy-mono);
               font-size: .65rem; line-height: 1; color: var(--mud-palette-text-secondary); }

/* Two series, so identity is never colour alone: a swatch AND its name, above the plot. */
.isy-legend { display: flex; flex-wrap: wrap; gap: .3rem 1rem; font-size: .78rem; color: var(--mud-palette-text-secondary); }
.isy-legend__i { display: inline-flex; align-items: center; gap: .35rem; }
.isy-legend__s { width: 10px; height: 10px; border-radius: 2px; flex: 0 0 auto; }

/* The call list ranks by money, so the money cell carries its own bar. It sits behind the digits at low
   opacity — a ranking cue, not a second reading of the number, which the digits already give exactly. */
.isy-callbar { position: relative; }
/* Anchored physically right, the side .isy-num keeps its digits on in both languages: the bar then
   grows out from under its own number instead of away from it. */
.isy-callbar::before { content: ""; position: absolute; inset-block: 2px; right: 0; border-radius: 3px;
                       background: var(--mud-palette-error); opacity: .13; width: var(--w, 0%); }
.isy-callbar > span { position: relative; }

/* The lateness ladder needs four steps that stay apart, so it runs amber -> orange -> red -> dark red:
   one warm ramp, monotonic, and nothing on it borrows brass, which now means "money collected" on the
   chart beside it. The first two rungs were brass and amber and rendered as the same colour. */
.isy-hbar__b--warn2 { background: color-mix(in srgb, var(--mud-palette-warning) 45%, var(--mud-palette-error)); }
.isy-hbar__b--worst { background: color-mix(in srgb, var(--mud-palette-error) 72%, #000); }

/* "How do I pay this?" — the one row of next steps under the open lines. It hugs the last charge card
   rather than sitting in a panel of its own: it is a footnote to those lines, not a section. */
.isy-settle { display: flex; align-items: center; gap: .4rem .6rem; flex-wrap: wrap; margin-top: .6rem; }
.isy-settle__l { font-size: .82rem; color: var(--mud-palette-text-secondary); }

/* A write-off in the money history: real, and not a payment. Italic and dimmed, the same treatment the
   charge card gives the same fact, so the two never read as two different kinds of event. */
.isy-hist--adj td { font-style: italic; opacity: .75; }

/* ---- support page (6 Sep 2026) -------------------------------------------------------------------
   Contact used to be a half-width panel that read "not configured yet" and nothing else. It is the
   hero now: one tile per channel, each a real link, so the page opens with the action instead of an
   apology. Auto-fit, because one configured channel must not sit in a third of the row. */
.isy-contact { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: .75rem; }
.isy-contact__i { display: flex; align-items: center; gap: .8rem; padding: .8rem .9rem; border-radius: 8px;
                  border: 1px solid var(--mud-palette-lines-default); background: var(--mud-palette-surface);
                  color: inherit; text-decoration: none; }
.isy-contact__i:hover { box-shadow: var(--mud-elevation-2); }
.isy-contact__ic { display: inline-flex; align-items: center; justify-content: center; width: 2.6rem; height: 2.6rem;
                   border-radius: 8px; flex-shrink: 0;
                   background: color-mix(in srgb, var(--mud-palette-primary) 12%, transparent);
                   color: var(--mud-palette-primary); }
.isy-contact__t { display: flex; flex-direction: column; gap: .05rem; min-width: 0; }
.isy-contact__l { font-size: .75rem; color: var(--mud-palette-text-secondary); }
.isy-contact__v { font-size: 1.05rem; font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
.isy-contact__a { font-size: .75rem; font-weight: 600; color: var(--mud-palette-primary); }

/* WhatsApp is how these customers actually write, so it is the one tile that carries a brand colour —
   and the only place in the portal where a colour outside the palette is allowed, because it is an
   identity, not a status. */
.isy-contact__i--wa { border-color: color-mix(in srgb, #25D366 55%, transparent);
                      background: color-mix(in srgb, #25D366 8%, var(--mud-palette-surface)); }
.isy-contact__i--wa .isy-contact__ic { background: color-mix(in srgb, #25D366 20%, transparent); color: #128C7E; }
.isy-contact__i--wa .isy-contact__a { color: #128C7E; }

/* Working hours is a fact, not a link: no pointer, no lift on hover. */
.isy-contact__i--static { cursor: default; }
.isy-contact__i--static:hover { box-shadow: none; }

.isy-send { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }

/* The exact text the send buttons carry — folded away, never hidden. It is the only block on the page
   that is deliberately LTR: it is a plain-text message, and its ASCII labels lead every line. */
.isy-raw { margin-top: .9rem; }
.isy-raw > summary { cursor: pointer; font-size: .8rem; color: var(--mud-palette-text-secondary); }
.isy-raw > summary:hover { color: var(--mud-palette-text-primary); }
.isy-raw pre { margin: .5rem 0 0; padding: .6rem .8rem; border-radius: 6px;
               border: 1px solid var(--mud-palette-lines-default); background: var(--mud-palette-background-grey);
               font-family: var(--isy-mono); font-size: .78rem; line-height: 1.7;
               white-space: pre-wrap; overflow-wrap: anywhere; direction: ltr; unicode-bidi: isolate;
               text-align: start; max-height: 22rem; overflow: auto; }

/* ---- sign in ------------------------------------------------------------------------------------
   Mirrors .login-wrap/.login-card in the public site's admin sheet, so arriving here from
   isystems.app reads as the next page rather than a different product. */
.isy-login { min-height: 100vh; display: grid; place-items: center; padding: 1.5rem; background: var(--isy-ground); }
.isy-login__card { width: min(400px, 100%); border: 1px solid var(--mud-palette-lines-default); border-radius: 10px; }
.isy-login__brand { text-align: center; margin-bottom: 1.5rem; }
.isy-login__brand img { height: 46px; width: auto; margin: 0 auto .6rem; display: block; }
.isy-login__name { font-size: 1.25rem; font-weight: 700; color: var(--isy-navy); line-height: 1.2; }
.isy-login__tag { font-size: .82rem; color: var(--mud-palette-text-secondary); margin-top: .15rem; }
.isy-login__label { display: block; font-weight: 600; font-size: .85rem; margin-bottom: .3rem; }
.isy-input { width: 100%; padding: .6rem .75rem; border: 1px solid var(--mud-palette-lines-default);
             border-radius: 6px; font: inherit; background: var(--mud-palette-surface); color: var(--mud-palette-text-primary); }
.isy-input:focus { border-color: var(--isy-green); outline: 2px solid color-mix(in srgb, var(--isy-green) 35%, transparent); outline-offset: 1px; }
.isy-login__btn { width: 100%; border: none; cursor: pointer; border-radius: 6px; padding: .65rem 1.1rem;
                  font: 600 .95rem inherit; font-family: inherit; background: var(--isy-green); color: #fff; }
.isy-login__btn:hover { background: var(--isy-green-deep); }
.isy-login__back { display: block; text-align: center; margin-top: 1.25rem; font-size: .85rem;
                   color: var(--isy-green-deep); text-decoration: none; }
.isy-login__back:hover { text-decoration: underline; }

/* the dark card needs its own ground: navy, not the light grey */
.mud-theme-dark .isy-login, [data-mud-theme="dark"] .isy-login { background: var(--mud-palette-background); }
.mud-theme-dark .isy-login__name, [data-mud-theme="dark"] .isy-login__name { color: var(--mud-palette-text-primary); }

/* ---- status chips --------------------------------------------------------------------------------
   With green as the brand accent, a SOLID green "active" pill and a SOLID green action button read as
   the same object. The public site's back-office never fills a status pill — it tints it and keeps the
   colour in the text (.pill.pub / .pill.draft in admin.css). Same rule here: a solid fill means "press
   me", a tint means "this is the state". Primary and secondary chips are left filled: those are
   selections and actions, not statuses. */
.mud-chip.mud-chip-filled.mud-chip-color-success,
.mud-chip.mud-chip-filled.mud-chip-color-warning,
.mud-chip.mud-chip-filled.mud-chip-color-error,
.mud-chip.mud-chip-filled.mud-chip-color-info,
.mud-chip.mud-chip-filled.mud-chip-color-dark {
    background-color: var(--isy-chip-tint);
    color: var(--isy-chip-ink);
    font-weight: 600;
}
.mud-chip.mud-chip-filled.mud-chip-color-success { --isy-chip-ink: var(--mud-palette-success); }
.mud-chip.mud-chip-filled.mud-chip-color-warning { --isy-chip-ink: var(--mud-palette-warning); }
.mud-chip.mud-chip-filled.mud-chip-color-error   { --isy-chip-ink: var(--mud-palette-error); }
.mud-chip.mud-chip-filled.mud-chip-color-info    { --isy-chip-ink: var(--mud-palette-info); }
.mud-chip.mud-chip-filled.mud-chip-color-dark    { --isy-chip-ink: var(--mud-palette-dark); }
.mud-chip.mud-chip-filled.mud-chip-color-success,
.mud-chip.mud-chip-filled.mud-chip-color-warning,
.mud-chip.mud-chip-filled.mud-chip-color-error,
.mud-chip.mud-chip-filled.mud-chip-color-info,
.mud-chip.mud-chip-filled.mud-chip-color-dark { --isy-chip-tint: color-mix(in srgb, var(--isy-chip-ink) 14%, transparent); }
.mud-chip.mud-chip-filled.mud-chip-color-success .mud-icon-root,
.mud-chip.mud-chip-filled.mud-chip-color-warning .mud-icon-root,
.mud-chip.mud-chip-filled.mud-chip-color-error .mud-icon-root,
.mud-chip.mud-chip-filled.mud-chip-color-info .mud-icon-root,
.mud-chip.mud-chip-filled.mud-chip-color-dark .mud-icon-root { color: inherit; }

/* customer product spec sheet (27 Sep 2026) — label/value down the page, no KPI tiles */
.isy-spec { max-width: 70ch; }
/* Customer program page: spec sheet beside the release card; one column under 900px. */
.isy-spec--split { max-width: 78rem; display: grid; grid-template-columns: minmax(0, 1fr) minmax(18rem, 26rem); gap: 0 2.25rem; align-items: start; }
.isy-spec--split > .isy-spec__head { grid-column: 1 / -1; }
.isy-spec__side h2 { font-size: 1rem; margin: .7rem 0 .5rem; }
.isy-spec__card { background: var(--mud-palette-surface); border: 1px solid var(--mud-palette-lines-default); border-radius: 10px; padding: .9rem 1rem;
                  display: flex; flex-direction: column; gap: .45rem; }
.isy-spec__cardfoot { margin-top: .35rem; padding-top: .6rem; border-top: 1px solid var(--mud-palette-lines-default); display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
@media (max-width: 900px) { .isy-spec--split { grid-template-columns: 1fr; } }
.isy-spec__head { padding-block: .25rem 1rem; border-block-end: 2px solid var(--mud-palette-divider); margin-block-end: .5rem; }
.isy-spec__titlerow { display: flex; align-items: center; gap: .5rem 1rem; flex-wrap: wrap; }
.isy-spec__titlerow .isy-spec__title { flex: 1 1 auto; min-width: 0; }
.isy-spec__eyebrow { font-size: .78rem; color: var(--mud-palette-text-secondary); }
.isy-spec__title { font-size: 1.6rem; font-weight: 700; margin: .2rem 0 0; line-height: 1.3; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.isy-spec__id { font-size: .95rem; font-weight: 400; color: var(--mud-palette-text-secondary); }
.isy-spec__sub { margin: .3rem 0 0; font-weight: 600; }
.isy-spec__desc { margin: .5rem 0 0; line-height: 1.75; color: var(--mud-palette-text-secondary); font-size: .9rem; }
.isy-spec__chip { font-size: .72rem; padding: .1rem .55rem; border-radius: 999px; font-weight: 600; background: var(--mud-palette-action-default-hover); }
.isy-spec__chip--ok { background: rgba(10,102,71,.12); color: #0A6647; }
.isy-spec__chip--warn { background: rgba(179,84,30,.14); color: #B3541E; }
.isy-spec__dl { display: grid; grid-template-columns: minmax(8rem, 11rem) 1fr; gap: 0 1.25rem; margin: 0; }
.isy-spec__dl dt { padding-block: .7rem; font-size: .82rem; color: var(--mud-palette-text-secondary); border-block-start: 1px solid var(--mud-palette-lines-default); }
.isy-spec__dl dd { padding-block: .7rem; margin: 0; border-block-start: 1px solid var(--mud-palette-lines-default); }
.isy-spec__strong { font-weight: 700; }
.isy-spec__dim { color: var(--mud-palette-text-secondary); }
.isy-spec__note { font-size: .8rem; color: var(--mud-palette-text-secondary); margin-block-start: .3rem; line-height: 1.6; }
.isy-spec__sec { margin-block-start: 1.75rem; padding-block-start: 1rem; border-block-start: 2px solid var(--mud-palette-divider); }
.isy-spec__sec h2 { font-size: 1rem; margin: 0 0 .5rem; }
.isy-spec__rel { padding: .6rem 0; border-block-start: 1px solid var(--mud-palette-lines-default); }
.isy-spec__rel--mine { border-inline-start: 3px solid var(--mud-palette-primary); padding-inline-start: .6rem; }
.isy-spec__relh { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.isy-spec__relnote { font-size: .87rem; margin-block-start: .35rem; line-height: 1.7; white-space: pre-wrap; }
.isy-spec__relnote--mine { border-inline-start: 3px solid var(--mud-palette-info); padding-inline-start: .6rem; color: var(--mud-palette-text-secondary); }
.isy-spec__badges { display: flex; gap: .4rem; flex-wrap: wrap; }
.isy-spec__badge { display: inline-flex; align-items: center; gap: .25rem; font-size: .78rem; padding: .2rem .6rem; border-radius: 999px;
                   background: var(--mud-palette-action-default-hover); border: 1px solid var(--mud-palette-lines-default); cursor: pointer;
                   color: inherit; text-decoration: none; font-family: inherit; line-height: 1.5; }
.isy-spec__badge:hover { box-shadow: var(--mud-elevation-2); }
.isy-spec__badge--dl { background: rgba(10,102,71,.1); border-color: rgba(10,102,71,.35); color: #0A6647; font-weight: 600; }
/* Save while it works, and an upload's progress (SaveButton, UploadProgress). */
.isy-save .mud-button-label { display: inline-flex; align-items: center; gap: .5rem; }
.isy-save__spin { width: 16px !important; height: 16px !important; color: inherit; }
.isy-upload { margin-block-start: .75rem; }
.isy-upload__t { display: flex; justify-content: space-between; font-size: .85rem; color: var(--mud-palette-text-secondary); margin-block-end: .25rem; }
/* An accessory's details: install steps as the staff wrote them, line by line, then the file. */
.isy-dep__steps p { margin: 0 0 .4rem; line-height: 1.8; }
.isy-dep__steps a { color: var(--isy-green-deep); text-decoration: underline; word-break: break-all; }
.isy-dep__file { display: flex; align-items: center; gap: .6rem; margin-block-start: 1.25rem; padding: .6rem .75rem;
                 border: 1px solid var(--mud-palette-lines-default); border-radius: 8px; }
.isy-dep__ficon { color: var(--isy-green-deep); flex-shrink: 0; }
/* Name over size, both at the start; the name is a file name, so it reads LTR but aligns with the RTL line. */
.isy-dep__fmeta { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; }
.isy-dep__fname { max-width: 100%; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.isy-dep__fsize { font-size: .8rem; color: var(--mud-palette-text-secondary); }
.isy-spec__key { flex-shrink: 0; margin-inline-start: auto; }   /* the row's inline end: left in RTL */
@media (max-width: 700px) { .isy-spec__dl { grid-template-columns: 1fr; } .isy-spec__dl dd { padding-block-start: 0; border-block-start: 0; } }

/* /admin/jobs: one card per job. Settings on one row, the save line under them, then the manual run. */
.isy-job__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
.isy-job__settings { display: grid; grid-template-columns: 1fr 1fr minmax(8rem, 10rem); gap: 16px 24px; align-items: start; }
.isy-job__save { display: flex; align-items: center; gap: 12px; margin-top: 12px; }
.isy-job__run { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.isy-job__company { flex: 0 1 18rem; margin: 0; }
.isy-job__summary { font-size: .85rem; }
.isy-job__rules { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px 24px; }
.isy-job__rule { display: flex; align-items: flex-start; gap: 8px; }
/* The run log: one grid, every run a subgrid, so times, starters, results and durations line up. */
.isy-runs { display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto auto; border: 1px solid var(--mud-palette-lines-default); border-radius: 6px; }
.isy-run { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; align-items: center; column-gap: 16px; padding: 8px 12px; font-size: .875rem; }
.isy-run + .isy-run, .isy-run__lines + .isy-run { border-top: 1px solid var(--mud-palette-lines-default); }
.isy-run--link { cursor: pointer; }
.isy-run--link:hover, .isy-run--open { background: var(--mud-palette-action-default-hover); }
.isy-run__at { white-space: nowrap; }
.isy-run__how { color: var(--mud-palette-text-secondary); white-space: nowrap; }
.isy-run__dur { color: var(--mud-palette-text-secondary); font-size: .8rem; }
.isy-run__lines { grid-column: 1 / -1; padding: 4px 12px 12px; background: var(--mud-palette-background-grey); }
/* A phone: one run is two lines read in order — when, how it started and how long it took, with the
   chevron at the far end — and what it did under them. The two-column grid it had scattered those four
   facts to the two edges and a third line (owner, 3 Nov 2026). */
@media (max-width: 700px) {
  .isy-job__settings, .isy-job__rules { grid-template-columns: 1fr; }
  .isy-runs { display: block; }
  .isy-run { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 10px; }
  .isy-run__at { order: 1; }
  .isy-run__how { order: 2; }
  .isy-run__dur { order: 3; }
  .isy-run__chev { order: 4; margin-inline-start: auto; }
  .isy-run__what { order: 5; flex: 1 1 100%; }
  .isy-run__lines { overflow-x: auto; }
}

/* A page with nothing to show but a reason: no access, not found. */
.isy-empty-page { display: flex; flex-direction: column; align-items: center; gap: 12px; text-align: center; padding: 64px 16px; }

/* The phone card cell of the main lists (see the phone block below): absent on a desk. */
.mud-table-cell.isy-rowcard, th.isy-rowcard { display: none; }
/* Card parts. The head carries the name and, at the far end, the state; the facts under it are short
   label–value pairs that wrap as a line of text would, in reading order. Nothing is pushed to the
   other edge: the card is read top-down from its start edge, like any Arabic text. */
.isy-rc__h { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.isy-rc__t { font-weight: 600; font-size: .95rem; line-height: 1.4; min-width: 0; overflow-wrap: anywhere; }
.isy-rc__s { font-size: .82rem; color: var(--mud-palette-text-secondary); overflow-wrap: anywhere; }
.isy-rc__f { display: flex; flex-wrap: wrap; gap: 2px 14px; font-size: .85rem; }
.isy-rc__f > span { display: inline-flex; align-items: baseline; gap: 5px; white-space: nowrap; }
.isy-rc__f i { font-style: normal; font-size: .72rem; color: var(--mud-palette-text-secondary); }
.isy-rc__f b { font-weight: 500; }
.isy-rc__tel { font-family: var(--isy-mono); direction: ltr; unicode-bidi: isolate; color: var(--isy-green-deep); text-decoration: none; }
/* the row's actions, at the card's foot, at its start edge — where a thumb reaches first */
.isy-rc__a { display: flex; align-items: center; gap: 2px; margin-top: 2px; }
.isy-tag--off { background: var(--mud-palette-background-grey); color: var(--mud-palette-text-secondary); }

/* ---- phones -------------------------------------------------------------------------------------
   The page body: 24px gutters on a desk, 12px on a phone, and on a phone the page ends above the
   assistant button (bottom-start, 56px tall, 20px up) instead of under it — the pager of every list
   sat behind that button. */
.isy-main { padding-inline: 24px; padding-bottom: 32px; }

/* Below 600px MudTable is in small-device mode (Breakpoint.Xs, its default): the head row is gone and
   every cell is one line, its DataLabel at the start and its value at the end. The pages give every
   cell its label and hide the cells nobody needs on a phone (HideSmall); what follows is what the
   library leaves wrong at that width, measured on the Companies page (3 Nov 2026). */
@media (max-width: 700px) {
  /* The global search does not fit beside the brand, the menu, the bell and the name. The company list
     and the registration log carry their own search. */
  .isy-gsearch { display: none; }
}
@media (max-width: 600px) {
  .isy-main { padding-inline: 12px; padding-bottom: 96px; }
  .isy-brand { margin-inline: 0 .25rem; }
  /* the user menu keeps its icon and drops the name — "…sam" cut at the window edge named nobody */
  .isy-usermenu .mud-button-label { font-size: 0; }
  .isy-usermenu .mud-button-icon-start { margin: 0; }
  .isy-usermenu .mud-button-icon-end { display: none; }
  /* a 34px heading is a poster on a 360px screen */
  .mud-typography-h4 { font-size: 1.5rem; }

  /* Table toolbar: each control on a line of its own, the whole width. The spacer has nothing to push
     against, and the widths set for the desk row (a 160px status picker, a 280px search) are lifted. */
  .mud-table-toolbar > * { flex: 1 1 100%; max-width: none !important; margin-inline-end: 0 !important; }
  .mud-table-toolbar > .mud-spacer { display: none; }
  .mud-table-toolbar .mud-select .mud-input-control { max-width: none !important; }
  .mud-table-toolbar .isy-tbfield--nolabel { margin-top: 0; }

  /* Stacked cells read as a FORM, from the start edge: a label column of one width, then the value
     right beside it, so every value in the list starts on the same line. MudBlazor spreads the two to
     opposite ends of the line, which in Arabic leaves the value stranded at the far left, a hand's
     width from the word that names it (owner, 3 Nov 2026). */
  .mud-xs-table .mud-table-cell { justify-content: flex-start; gap: 8px; min-height: 34px; }
  .mud-xs-table .mud-table-cell:before { font-size: .75rem; color: var(--mud-palette-text-secondary); flex: 0 0 6.5rem; padding: 0; }
  .mud-xs-table .mud-table-cell > * { min-width: 0; }
  /* A hidden cell (HideSmall) is gone, not a blank 36px line: MudBlazor collapses it, which on a flex
     cell only blanks it. And the card's edge is the row's, not its last cell's — the last cell is often
     the hidden one (the audit's data icon, a code page's empty column), and the cards ran together. */
  .mud-xs-table .mud-table-cell.mud-table-cell-hide { display: none; }
  .mud-xs-table .mud-table-body .mud-table-row { display: block; padding-block: 6px; border-bottom: 1px solid var(--mud-palette-table-lines); }
  .mud-xs-table .mud-table-row .mud-table-cell:last-child { border-bottom: 0; }
  /* A cell's second line (the edition under a version, the k under a licensee) goes under the value, the
     whole width — as a flex item beside it, it painted over the version. */
  .mud-xs-table .mud-table-cell:has(.isy-cellsub) { flex-wrap: wrap; }
  .mud-xs-table .mud-table-cell .isy-cellsub { flex: 1 1 100%; max-width: none; padding-inline-start: calc(6.5rem + 8px); }

  /* ---- row cards. The main lists do not stack their columns on a phone: each row renders ONE extra
     cell that holds a card designed for the phone — the name, the one or two facts a call needs, the
     state as a tag — and every other cell is hidden (HideSmall). On a desk that cell does not exist. */
  .mud-xs-table .mud-table-cell.isy-rowcard { display: flex; flex-direction: column; align-items: stretch; gap: 3px; padding: 10px 16px; }
  .mud-xs-table .mud-table-cell.isy-rowcard:before { content: none; }
  /* a long value in a tile (a file name) breaks instead of leaving the tile */
  .isy-kpi__v { min-width: 0; overflow-wrap: anywhere; }
  /* the pager keeps its two arrows and the count; the rows-per-page picker and its caption are dropped */
  .mud-xs-table .mud-table-pagination-display:has(.mud-table-pagination-select) { display: none; }

  /* The licence filter (my products, the company's licences tab): the search takes the whole first line,
     the chips the next one together — beside a 300px search, «الكل» stood alone at the far edge and
     «المفضلة» fell to a line of its own. */
  .isy-lic-filter > .mud-input-control { flex: 1 1 100%; max-width: none !important; }
  /* A product card: the name is one line on a phone, so the two-line reserve that lines desk cards up
     only left a blank band through the middle of every card. */
  .isy-product { min-height: 0; }
  .isy-product__name { min-height: 0; }
  /* The assistant settings form: each control the whole line, the audience name on a line of its own. */
  .isy-settings .mud-select, .isy-settings .mud-input-control { flex: 1 1 100%; width: 100%; max-width: none !important; }
  .isy-settings__who { flex: 1 1 100%; }
  .isy-settings > div:has(> .mud-input-control) { flex-direction: column; align-items: stretch; }

  /* Dialogs use the width: MudBlazor leaves 32px each side, which on a 360px phone is a 296px form. */
  .mud-dialog.mud-dialog-width-full { width: calc(100% - 16px); }
  .mud-dialog { max-height: calc(100dvh - 16px); }

  /* A simple table (dashboard lists, statements, insights): the figures, the dates and the headings never
     break, the names may — a name on two lines beats three columns cut off at the card's edge. The
     container still scrolls sideways when even that is not enough. */
  .mud-simple-table th, .mud-simple-table .isy-mono, .dh-table .isy-mono { white-space: nowrap; }
  /* MudGrid reaches 12px past its box on each side (its items pad it back); with the 12px gutter here
     that is the page's edge, and the page scrolled sideways by that much — the heading lost its first
     letter. The items are stacked on a phone anyway, so the grid keeps to its box. */
  .isy-main .mud-grid { margin-inline: 0; width: 100%; }
  .isy-main .mud-grid > .mud-grid-item { padding-inline: 0; }
  /* tabs: a chip-sized tab, three or four to a row, instead of two half-width ones (MudTabs puts its
     160px MinimumTabWidth on each tab inline, hence the !important) */
  .isy-tabs .mud-tab { min-width: 0 !important; padding-inline: 10px; min-height: 42px; }
  /* Stacked rows are blocks inside a table that still sizes itself from their content: one cell with a
     long unbreakable run (a key chip, a clamped sub-line — a -webkit-box reports its unwrapped width)
     made the whole list wider than the card and it scrolled sideways. Fixed layout: the one column IS
     the card's width, and the flex lines inside it shrink to fit. */
  .mud-xs-table .mud-table-root { table-layout: fixed; }
  /* The users list: a company's accounts stand under their label, one per line — as a flex ROW the
     accounts of a six-person company lined up sideways and pushed the table off the card. */
  .mud-xs-table .isy-ugrp__users { flex-direction: column; align-items: stretch; }
  .mud-xs-table .isy-ugrp__users:before { align-self: flex-start; }
  .mud-xs-table .isy-ugrp__u { justify-content: flex-start; }
  /* simple tables: four columns of figures fit a 360px card at this size, with no sideways scroll */
  .mud-simple-table { font-size: .8rem; }
  .mud-simple-table table tr > td, .mud-simple-table table tr > th,
  .mud-simple-table.mud-table-dense table tr > td, .mud-simple-table.mud-table-dense table tr > th { padding-inline: 8px; }

  /* The rollout rows: four columns on a desk, the program on its own line on a phone. */
  .isy-rollout { display: block; }
  .isy-rollout__row { display: flex; flex-wrap: wrap; gap: 2px 14px; padding-block: 4px; }
  .isy-rollout__row > b { flex-basis: 100%; }
  /* a 15rem label column left 60px for the bar */
  .isy-hbar--wide { grid-template-columns: minmax(0, 7.5rem) minmax(2rem, 1fr) minmax(0, max-content); }
  /* the statement header: the four figures under the switch, not beside it */
  .isy-ledger--head { flex-basis: 100%; justify-content: flex-start; }
  /* the money page's own toolbar group already stacks its controls (above); the users bar too */
}
