/* =====================================================================
   Albatriq | بتريق  -  design system
   One stylesheet for the public site, the dashboard and the point of sale.
   ===================================================================== */
:root {
    /* brand: a deep tax-authority navy with the logo's gold as the accent */
    --brand-900: #0b1f3a;
    --brand-800: #10294b;
    --brand-700: #16365f;
    --brand-600: #1d4676;
    --brand-500: #2a5c96;
    /* the light end of the brand ramp: a tinted chip on a white card. It
       existed only as an inline fallback before, which is a shade nothing
       else can reuse. */
    --brand-200: #cfe0f2;
    --brand-050: #eef4fb;
    /* The gold in the البطريق mark. It was in the logo and nowhere else, so the
       brand stopped at the top corner of the sidebar and the rest of the
       product was navy and teal — the one colour a customer recognises us by
       appearing on no screen they spend time in. It has since replaced the teal
       accent entirely, so this ramp is what every accented control uses.

       There was a moment when the teal ramp had been **renamed** to `gold-*`
       and this block redefined the same four tokens underneath it: `--gold-600`
       was declared twice in one `:root`, teal first and gold second, so the
       whole product went orange by shadowing rather than by decision. The dead
       half is gone. Two definitions of one token in one block is a colour that
       changes the day somebody reorders the file.

       It is a **brand** colour, not a status one, and it has to stay
       distinguishable from `--warn-*` (#d97706), which is close enough to be
       confused with it. So the rule is: gold marks *ours*. It never means
       "careful", and nothing that means "careful" is gold. */
    --gold-700: #b8630b;
    --gold-600: #e07f10;
    --gold-500: #f79520;   /* the logo */
    --gold-400: #f9ae52;
    --gold-200: #fcd9a8;
    --gold-050: #fff6ea;

    --ink-900: #0f172a;
    --ink-700: #334155;
    --ink-500: #64748b;
    --ink-400: #94a3b8;
    --ink-300: #cbd5e1;
    --ink-200: #e2e8f0;
    --ink-100: #f1f5f9;
    --ink-050: #f8fafc;
    --surface: #ffffff;

    /* Each status family carries a tint, a border, a mid and a text shade. The
       -200 and -700 steps exist because alerts and banners had been written with
       the hex inline; a hex in a rule is a shade nothing else can reuse. */
    --ok-050: #ecfdf5;   --ok-200: #a7f3d0;  --ok-600: #059669;   --ok-700: #065f46;
    --warn-050: #fffbeb; --warn-200: #fde68a; --warn-600: #d97706; --warn-700: #92400e;
    --bad-050: #fef2f2;  --bad-200: #fecaca; --bad-600: #dc2626;  --bad-700: #991b1b;
    --info-050: #eff6ff; --info-200: #bfdbfe; --info-600: #2563eb; --info-700: #1e40af;

    --radius: 14px;
    --radius-sm: 9px;
    --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06), 0 1px 3px rgba(15, 23, 42, .05);
    --shadow-md: 0 4px 12px rgba(15, 23, 42, .07), 0 2px 4px rgba(15, 23, 42, .04);
    --shadow-lg: 0 18px 40px rgba(11, 31, 58, .12);
    --sidebar-width: 264px;
}

* { box-sizing: border-box; }

/* `[hidden]` is a UA rule of the lowest possible specificity, so **any** class
   that sets `display` beats it: `el.hidden = true` on a `.grid-2` or on a
   `.field .hint` left both of them on the screen. It looked like the script had
   not run. One rule, once, rather than a `.hidden` class remembered at each
   call site — and `!important` because the whole point is to outrank whatever
   the element's own class says its display is. */
[hidden] { display: none !important; }

/* ---------------------------------------------------------------- scrollbars
   The platform default is a wide grey bar that sits on top of the design and
   looks especially wrong inside the dark navy sidebar. These rules make every
   scrollable area use a thin bar in the surface's own palette. Overlay
   scrollbars (a Mac with a trackpad) ignore all of this, which is fine - the
   styling only shows up where a scrollbar is actually drawn. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--ink-300) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: var(--ink-300);
    border-radius: 999px;
    border: 3px solid transparent;   /* inset the thumb so it reads as slim */
    background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--ink-400); background-clip: content-box; }
*::-webkit-scrollbar-corner { background: transparent; }

body {
    margin: 0;
    font-family: 'Cairo', system-ui, -apple-system, 'Segoe UI', sans-serif;
    color: var(--ink-900);
    background: var(--ink-050);
    font-size: 15px;
    line-height: 1.7;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--brand-600); text-decoration: none; }
a:hover { color: var(--gold-700); }

h1, h2, h3, h4, h5 { font-weight: 700; line-height: 1.35; margin: 0 0 .6rem; letter-spacing: -.01em; }

.container-x { width: min(1180px, 92%); margin-inline: auto; }

/* ---------------------------------------------------------------- buttons */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
    border: 1px solid transparent; border-radius: var(--radius-sm);
    padding: .62rem 1.15rem; font-size: .95rem; font-weight: 600;
    font-family: inherit; cursor: pointer; transition: .16s ease; white-space: nowrap;
    /* the same line-height and floor as .input and .select, because a button
       standing next to either of them on a filter row has to be their height --
       it was 50px against a 39px select, and the row read as broken */
    line-height: 1.4; min-height: 2.7rem;
}
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-primary   { background: var(--brand-700); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--brand-800); color: #fff; transform: translateY(-1px); box-shadow: var(--shadow-md); }
/* One rule decides which gold a thing gets, and it is a contrast measurement
   rather than a preference. White on `--gold-600` (#e07f10) is **2.75:1** —
   under even the 3:1 floor for large text, so a cashier reading «تحصيل وإرسال»
   under a shop's lighting is guessing at it. White on `--gold-700` (#b8630b) is
   **4.35:1**, which carries a button label.

     a solid gold fill under light text   →  --gold-700
     gold used as text on a light ground  →  --gold-700
     gold as a mark: a rule, an underline, a border, a tint  →  --gold-500

   The bright gold is the logo's and stays where nothing has to be read out of
   it, which is most places it appears. */
.btn-accent    { background: var(--gold-700); color: #fff; }
.btn-accent:hover:not(:disabled) { background: var(--gold-600); color: #fff; transform: translateY(-1px); box-shadow: var(--shadow-md); }
/* An edge one shade off the page is not an edge. `--ink-200` is the colour of
   every card border, so an outline button standing on a card had a border the
   eye read as part of the card and a fill identical to it — the same complaint
   as `.btn-ghost` below, one step quieter. `--ink-300` and an explicit white
   fill give it a shape on a tinted ground as well as on a white one. */
.btn-outline   { background: var(--surface); color: var(--brand-700); border-color: var(--ink-300); }
.btn-outline:hover:not(:disabled) { border-color: var(--brand-600); color: var(--brand-800); background: var(--brand-050); }
/* #f1f5f9 on a white card is a two per cent difference. The button had no edge
   and almost no fill, so it read as a disabled control rather than as something
   to press — and it is the button under half the secondary actions in the
   product. A defined border is what makes a quiet button still a button. */
.btn-ghost     { background: var(--ink-050); color: var(--ink-700); border-color: var(--ink-300); }
.btn-ghost:hover:not(:disabled) { background: var(--ink-100); border-color: var(--ink-400); color: var(--ink-900); }
/* The brand's own button, for the one action a screen is really offering. */
.btn-gold      { background: var(--gold-500); color: #24160a; }
.btn-gold:hover:not(:disabled) { background: var(--gold-600); color: #24160a; transform: translateY(-1px); box-shadow: var(--shadow-md); }
.btn-danger    { background: var(--bad-600); color: #fff; }
.btn-danger:hover:not(:disabled) { background: #b91c1c; color: #fff; }
.btn-lg { padding: .85rem 1.7rem; font-size: 1.02rem; min-height: 3.1rem; }
.btn-sm { padding: .38rem .75rem; font-size: .84rem; min-height: 0; }
/* Read by a screen reader, drawn for nobody: a control whose label would
   otherwise be only a placeholder or a tooltip still needs a real one. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.btn-block { width: 100%; }

/* An item's picture at list size. The placeholder is the same box rather than
   nothing, so a catalogue half filled in still has straight rows. */
.item-thumb {
    width: 40px; height: 40px; flex: 0 0 auto; border-radius: var(--radius-sm);
    object-fit: cover; border: 1px solid var(--ink-200); background: var(--surface);
}
/* `.no-pic`, not `.empty`: `.empty` is the design system's own component for
   an empty *state* — a padded, centred block with its own typography — and a
   40px thumbnail wearing it came out 98px tall. A modifier named after a
   general word will collide with the general thing eventually. */
.item-thumb.no-pic {
    display: grid; place-items: center; color: var(--ink-300);
    background: var(--ink-050); font-size: 1.05rem;
}

/* ---------------------------------------------------------------- cards */
.card {
    background: var(--surface); border: 1px solid var(--ink-200);
    border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.card-head {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: 1.05rem 1.35rem; border-bottom: 1px solid var(--ink-200);
}
.card-head h2, .card-head h3 { margin: 0; font-size: 1.05rem; }
.card-body { padding: 1.35rem; }

/* ---------------------------------------------------------------- forms */
.field { margin-bottom: 1.05rem; }
.field > label { display: block; font-weight: 600; font-size: .9rem; margin-bottom: .38rem; color: var(--ink-700); }
.field .hint { display: block; font-size: .8rem; color: var(--ink-500); margin-top: .3rem; line-height: 1.5; }
.req { color: var(--bad-600); }

.input, .select, .textarea {
    width: 100%; padding: .62rem .85rem; font-family: inherit; font-size: .95rem;
    color: var(--ink-900); background: var(--surface);
    border: 1px solid var(--ink-200); border-radius: var(--radius-sm);
    transition: .15s ease;
    /* Both, explicitly. An <input> takes the page's line-height and a <select>
       uses the font's own whatever it is told, so with only the padding shared
       they came out 39px and 50px -- a select and a text box side by side on
       one row sat at visibly different heights. The min-height then holds the
       floor for whichever the browser still renders shorter. */
    line-height: 1.4; min-height: 2.7rem;
}
.input:focus, .select:focus, .textarea:focus {
    outline: none; border-color: var(--gold-500); box-shadow: 0 0 0 3px var(--gold-050);
}
.input:disabled, .select:disabled { background: var(--ink-100); color: var(--ink-500); }
.textarea { min-height: 110px; resize: vertical; }

/* A checkbox and its wording read as one control, so they share a line and the
   whole label is the hit target. Used unstyled in three templates before it was
   a component, which left the box and its text on different baselines. */
.check {
    display: inline-flex; align-items: center; gap: .55rem;
    font-weight: 500; font-size: .93rem; color: var(--ink-700);
    cursor: pointer; line-height: 1.4;
}
.check input[type="checkbox"], .check input[type="radio"] {
    width: 1rem; height: 1rem; flex: 0 0 auto; margin: 0; accent-color: var(--brand-600); cursor: pointer;
}
.select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2364748b' d='M6 8 0 0h12z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: left .85rem center; padding-left: 2.2rem; }
/* The arrow belongs on the side the reader finishes on. background-position has
   no logical form, so LTR needs saying explicitly. */
[dir="ltr"] .select { background-position: right .85rem center; padding-left: .85rem; padding-right: 2.2rem; }

/* A step down for a dense row of controls -- the till's buyer block, where a
   full-height field for each of four things leaves the basket 59px tall.
   After `.select` above, and repeating its physical paddings, because
   background-position has no logical form and the arrow decides which side the
   text has to keep clear of. */
.input-sm, .select-sm { padding: .34rem .6rem; font-size: .88rem; min-height: 0; }
.select-sm { padding-left: 1.9rem; background-position: left .6rem center; }
[dir="ltr"] .select-sm { padding-left: .6rem; padding-right: 1.9rem; background-position: right .6rem center; }

/* minmax(0, 1fr), not 1fr: a grid item's min-width defaults to `auto`, so a
   column refuses to shrink below its content's minimum. One wide table inside a
   card then pushes the whole card past the edge of the page and the document
   scrolls sideways -- and `.table-wrap`'s own overflow never gets the chance to
   scroll it instead. Zero lets the column shrink and hands the overflow back to
   the element built to handle it. */
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 1.1rem; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 1.1rem; }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1.1rem; }

/* ---------------------------------------------------------------- tables */
.table-wrap {
    overflow-x: auto;
    overscroll-behavior-x: contain;
}
/* the bar belongs inside the card, not overlapping its rounded corner */
.table-wrap::-webkit-scrollbar { height: 8px; }
table.data { width: 100%; border-collapse: collapse; font-size: .92rem; }
table.data th {
    /* `start`, not `right`. text-align takes no logical value from the document
       direction unless you give it one, so a header written `right` for Arabic
       stayed on the right in English while its own cells moved to the left --
       every column had its heading over the wrong end of itself. */
    text-align: start; font-weight: 700; font-size: .82rem; letter-spacing: .01em;
    color: var(--ink-500); background: var(--ink-050);
    padding: .75rem 1rem; border-bottom: 1px solid var(--ink-200); white-space: nowrap;
}
table.data td { padding: .8rem 1rem; border-bottom: 1px solid var(--ink-100); vertical-align: middle; }
/* Header and cell take their alignment from the same place, so a column's
   heading always sits over its own values.

   A numeric column needs saying explicitly, and physically. `.num` carries
   `unicode-bidi: plaintext`, which resolves the *paragraph* direction from the
   value's own first strong character -- a digit -- so inside an RTL table those
   cells become LTR paragraphs and `text-align: start` resolves to their LEFT
   while the heading above stays on the right. Every amount, date and id in the
   application sat on the opposite side of its own column because of it.

   `right`, physically, in both directions: a number's least significant digit is
   on its right whatever the page does, so right-aligning is what makes 51.30 and
   1026.00 share a decimal point. The heading is told the same thing so it stays
   over its own figures. */
/* `unicode-bidi: plaintext` above resolves each value's *paragraph* direction
   from its own first strong character, and `text-align: start/end` resolves
   against that paragraph -- not against the page. So a Latin code or a digit
   inside an Arabic page silently becomes an LTR paragraph and aligns itself to
   the LEFT, while the heading or label beside it stays on the right. It showed
   up as codes drifting away from their column headings and, on every summary
   tile in the application, as the figure sitting on the opposite side from its
   own caption. There is no logical keyword that means "the document's start"
   once plaintext is in play, so the edge is named per direction. */
[dir="rtl"] .num, [dir="rtl"] .mono { text-align: right; }
[dir="ltr"] .num, [dir="ltr"] .mono { text-align: left; }

/* A money column is the exception: right in both directions, because a number's
   least significant digit is on its right whatever the page does, and that is
   what makes 51.30 and 1026.00 share a decimal point. The heading carries .num
   too so it stays over its own figures. */
table.data th.num, table.data td.num { text-align: right; }
/* a numeric field inside such a cell puts its own value on the same edge, so a
   typed figure lines up with the column heading above it */
table.data td.num .input { text-align: right; }
table.data tbody tr:hover { background: var(--ink-050); }
table.data tbody tr:last-child td { border-bottom: 0; }
/* Numeric cells hold dates, times, amounts and units. Left to the RTL flow a
   value like "2026-09-06 01:12:54" renders with the time before the date, and
   "156 ms" reads as "ms 156". plaintext gives each value the direction its own
   first strong character implies, which is what these actually are. */
.num {
    font-variant-numeric: tabular-nums; font-feature-settings: "tnum";
    unicode-bidi: plaintext;
    /* an amount or a timestamp broken across two lines reads as two values;
       the table scrolls inside .table-wrap rather than wrapping these */
    white-space: nowrap;
}

/* Codes, UUIDs, serials and URLs are latin text sitting inside an Arabic page.
   plaintext lets each one pick its own direction from its first strong
   character, so a path like /connect/token is not reordered by the RTL flow. */
.mono {
    font-family: ui-monospace, 'SF Mono', Menlo, monospace;
    font-size: .84em; letter-spacing: -.02em;
    unicode-bidi: plaintext;
    /* a receipt number split at its hyphen looks like two numbers */
    white-space: nowrap;
}
input.mono {
    height: 50px;
}
/* A UUID is the one code long enough that it has to wrap. It breaks anywhere,
   because there is no meaningful boundary in it -- but it says so explicitly
   rather than inheriting the nowrap above. */
.mono-break { white-space: normal; overflow-wrap: anywhere; word-break: break-all; }
pre, code, .ltr { unicode-bidi: plaintext; }
.force-ltr { direction: ltr; text-align: left; }

/* ---------------------------------------------------------------- totals
   A label and its amount on opposite ends of a line, with the last one ruled
   off. It lived in pos.css, which only the till loads -- so the receipt, the
   customer and the subscription invoice screens were rendering it unstyled,
   as a stack of ragged text. A component four screens want belongs here. */
.totals { font-size: .93rem; }
.totals .row { display: flex; justify-content: space-between; gap: 1rem; padding: .28rem 0; color: var(--ink-700); }
.totals .row > span:last-child { white-space: nowrap; }
.totals .row.grand {
    border-top: 2px dashed var(--ink-200); margin-top: .5rem; padding-top: .7rem;
    font-size: 1.3rem; font-weight: 800; color: var(--ink-900);
}
/* the panel sits at the end of its card rather than filling the width, because
   a total stretched across a wide card loses its label */
.totals-panel { max-width: 24rem; margin-inline-start: auto; }

/* ---------------------------------------------------------------- badges */
.badge {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .2rem .6rem; border-radius: 999px;
    font-size: .78rem; font-weight: 700; white-space: nowrap;
}
.badge-ok   { background: var(--ok-050);   color: var(--ok-600); }
.badge-warn { background: var(--warn-050); color: var(--warn-600); }
.badge-bad  { background: var(--bad-050);  color: var(--bad-600); }
.badge-info { background: var(--info-050); color: var(--info-600); }
.badge-mute { background: var(--ink-100);  color: var(--ink-500); }

/* ---------------------------------------------------------------- alerts */
.alert {
    display: flex; gap: .7rem; align-items: flex-start;
    padding: .85rem 1.1rem; border-radius: var(--radius-sm);
    border: 1px solid transparent; font-size: .92rem; margin-bottom: 1rem;
}
.alert-ok   { background: var(--ok-050);   border-color: var(--ok-200);   color: var(--ok-700); }
.alert-bad  { background: var(--bad-050);  border-color: var(--bad-200);  color: var(--bad-700); }
.alert-warn { background: var(--warn-050); border-color: var(--warn-200); color: var(--warn-700); }
.alert-info { background: var(--info-050); border-color: var(--info-200); color: var(--info-700); }

/* -------------------------------------------------------------- module cards
   The catalogue, rendered in two places: the public site's modules page and the
   store a subscriber orders from. Cards rather than a table -- each one is a
   decision with a price and a set of prerequisites, not a row to scan.
   auto-fill with a min of 20rem gives four across on a desktop and one on a
   phone without a breakpoint of its own.

   Shared for the same reason the plan cards are, arrived at from the other
   side: this lived in `app.css`, and the site layout does not load that sheet,
   so the marketing page would have rendered the cards unstyled. Before putting
   a component in either sheet, ask whether the other layout will want it. */
.modules {
    display: grid; gap: 1rem; margin-bottom: 1.2rem;
    grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
}
/* A column, so the cards in a row end together and the price at the bottom of
   each lines up with the price beside it. Without it every card is as tall as
   its own bullet list and the footers stagger down the row — which reads as a
   rendering fault rather than as a difference in content. */
.module-card { display: flex; transition: border-color .15s, box-shadow .15s; }
.module-card > .card-body { display: flex; flex-direction: column; flex: 1; }
.module-card:hover { border-color: var(--brand-200); box-shadow: var(--shadow-md); }
.module-card.is-on { border-color: var(--ok-200); background: linear-gradient(180deg, var(--ok-050), var(--surface) 40%); }

.module-head { display: flex; align-items: flex-start; gap: .8rem; margin-bottom: .8rem; }
.module-head h3 { margin: 0; font-size: 1.05rem; }
.module-head .hint { margin: .15rem 0 0; }
.module-ico {
    width: 40px; height: 40px; border-radius: 11px; flex: 0 0 auto;
    display: grid; place-items: center; font-size: 1.15rem;
    background: var(--brand-050); color: var(--brand-700);
}
.is-on .module-ico { background: var(--ok-050); color: var(--ok-600); }

.module-price { margin-bottom: .8rem; }
.module-price strong { font-size: 1.7rem; font-weight: 800; color: var(--ink-900); }
.module-price .hint { margin-inline-start: .3rem; }

/* The bullets take the slack. Everything below them — what the module needs,
   and the price — is then pinned to the bottom of every card alike. */
.module-features { list-style: none; margin: 0 0 .9rem; padding: 0; font-size: .88rem; flex: 1; }
.module-features li { display: flex; gap: .45rem; padding: .12rem 0; color: var(--ink-700); }
.module-features li i { color: var(--ok-600); flex: 0 0 auto; margin-top: .3rem; }

.module-needs { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; margin-bottom: .5rem; }

.module-foot {
    display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
    border-top: 1px solid var(--ink-200); padding-top: .8rem; margin-top: auto;
}
.module-foot .check { margin: 0; }

/* ---------------------------------------------------------------- plan cards
   Shared: the pricing section of the public site and the subscription screen
   inside the application render the same card, so this lives in the design
   system rather than in site.css. It was only in site.css once, and the
   subscription screen rendered the cards completely unstyled because the
   application layout does not load that sheet. */
.plans {
    display: grid;
    /* auto-fit keeps three across on the marketing page and folds to two or one
       inside the narrower application content column */
    grid-template-columns: repeat(auto-fit, minmax(248px, 1fr));
    gap: 1.5rem; align-items: start;
}
.plan {
    background: var(--surface); border: 1px solid var(--ink-200); border-radius: 18px;
    padding: 2rem 1.7rem; position: relative; transition: .18s ease;
}
.plan:hover { box-shadow: var(--shadow-lg); transform: translateY(-3px); }
.plan.popular { border: 2px solid var(--gold-500); box-shadow: var(--shadow-lg); }
.plan .tag {
    position: absolute; top: -13px; inset-inline-end: 50%; transform: translateX(-50%);
    background: var(--gold-700); color: #fff; padding: .25rem .95rem;
    border-radius: 999px; font-size: .78rem; font-weight: 700; white-space: nowrap;
}
.plan h3 { font-size: 1.2rem; margin-bottom: .2rem; }
.plan .plan-desc { color: var(--ink-500); font-size: .9rem; min-height: 2.6em; margin-bottom: 1.2rem; }
.plan .price { display: flex; align-items: baseline; gap: .35rem; margin-bottom: .3rem; }
.plan .price .amount { font-size: 2.5rem; font-weight: 800; color: var(--brand-900); line-height: 1; }
.plan .price .per { color: var(--ink-500); font-size: .92rem; }
.plan .save { color: var(--ok-600); font-size: .85rem; font-weight: 600; min-height: 1.4em; }
.plan ul { list-style: none; padding: 0; margin: 1.4rem 0; }
.plan li { display: flex; gap: .6rem; align-items: flex-start; padding: .42rem 0; font-size: .93rem; color: var(--ink-700); }
.plan li .tick { color: var(--ok-600); flex: 0 0 auto; font-weight: 800; }
.plan li.off { color: var(--ink-400); }
.plan li.off .tick { color: var(--ink-400); }

.cycle-switch { display: inline-flex; background: var(--ink-100); border-radius: 999px; padding: .28rem; }
.cycle-switch button {
    border: 0; background: transparent; font-family: inherit; font-weight: 700; font-size: .92rem;
    padding: .45rem 1.4rem; border-radius: 999px; cursor: pointer; color: var(--ink-500); transition: .15s;
}
.cycle-switch button.on { background: #fff; color: var(--brand-800); box-shadow: var(--shadow-sm); }

/* ---------------------------------------------------------------- utilities */
.muted { color: var(--ink-500); }
.small { font-size: .85rem; }
.text-center { text-align: center; }
.mt-0 { margin-top: 0; } .mt-1 { margin-top: .5rem; } .mt-2 { margin-top: 1rem; } .mt-3 { margin-top: 1.5rem; } .mt-4 { margin-top: 2rem; }
.mb-0 { margin-bottom: 0; } .mb-1 { margin-bottom: .5rem; } .mb-2 { margin-bottom: 1rem; } .mb-3 { margin-bottom: 1.5rem; }
.flex { display: flex; } .items-center { align-items: center; } .justify-between { justify-content: space-between; }
.gap-1 { gap: .5rem; } .gap-2 { gap: 1rem; } .wrap { flex-wrap: wrap; }
/* Pushes an item to the far end of a flex row. Logical, so it is the left in
   Arabic and the right in English without being written twice — `mr-auto` would
   have been a physical property and wrong in one of the two languages. */
.push-end { margin-inline-start: auto; }
.hidden { display: none !important; }

@media (max-width: 880px) {
    .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------------
   Language switcher

   Two short labels rather than a dropdown: there are two languages and the
   choice is made rarely, so a control that shows both at once and costs one
   click beats a menu that costs two and hides the alternative.
   --------------------------------------------------------------------------- */
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.lang-opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 700;
  line-height: 1.6;
  color: var(--ink-500);
  text-decoration: none;
  /* each label reads in its own script's direction, whatever the page is set to */
  unicode-bidi: plaintext;
}
.lang-opt:hover { background: var(--ink-050); color: var(--ink-900); }
.lang-opt.on    { background: var(--brand-600); color: var(--surface); }

/* ---------------------------------------------------------------- dialog
   The application's own confirm, replacing `window.confirm()` -- see
   `layouts/_dialog.tpl` for why. A real <dialog>, so the backdrop, the focus
   trap and Escape come from the browser and only the look is ours. */
dialog.dlg {
    border: 1px solid var(--ink-200); padding: 0;
    border-radius: 18px;
    background: var(--surface); color: var(--ink-700);
    box-shadow: 0 24px 64px -12px rgba(15, 23, 42, .32), 0 0 0 1px rgba(15, 23, 42, .04);
    width: min(30rem, calc(100vw - 2.5rem));
    /* a dialog inherits nothing from the page, so the direction and the face
       are set again or an Arabic message lays out left to right inside it */
    direction: inherit; font-family: inherit;
    overflow: hidden;
}
dialog.dlg::backdrop {
    background: rgba(15, 23, 42, .5);
    backdrop-filter: blur(2px);
}
/* It arrives rather than appearing.
   A keyframe on [open], not a transition from `opacity: 0` on the base rule:
   the transition version needs `@starting-style` and `transition-behavior` to
   run at all, and when any part of that is not honoured the dialog is left
   sitting at zero opacity -- open, focus trapped, and invisible. An animation
   cannot fail that way, because its end state is the element's own. */
dialog.dlg[open] { animation: dlg-in .18s cubic-bezier(.2, .8, .3, 1); }
dialog.dlg[open]::backdrop { animation: dlg-fade .18s ease; }
/* Transform only, deliberately: an animation that never runs to completion --
   a throttled background tab, a paused renderer -- leaves the element on its
   first frame. Stuck on a 10px offset is a dialog that looks fine; stuck on
   `opacity: 0` is a dialog that is open, has the focus trapped inside it, and
   cannot be seen. This one gates deleting a branch, so it never fades. */
@keyframes dlg-in {
    from { transform: translateY(10px) scale(.97); }
    to   { transform: none; }
}
@keyframes dlg-fade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
    dialog.dlg[open], dialog.dlg[open]::backdrop { animation: none; }
}

.dlg-body { display: block; }
.dlg-head { display: flex; gap: 1rem; align-items: flex-start; padding: 1.6rem 1.6rem 1.3rem; }
/* the tinted round icon the banners and the summary tiles use, so a question
   from the product looks like it came from the product */
.dlg-ico {
    width: 44px; height: 44px; border-radius: 13px; flex: 0 0 auto;
    display: grid; place-items: center; font-size: 1.2rem;
    background: var(--warn-050); color: var(--warn-600);
}
.dlg-copy { min-width: 0; flex: 1; }
/* the message is the heading: a generic "Confirm" above it said nothing the
   button did not already say */
.dlg-text {
    margin: 0; font-size: 1.06rem; font-weight: 800; line-height: 1.55;
    color: var(--ink-900);
}
.dlg-note { margin: .4rem 0 0; color: var(--ink-500); font-size: .92rem; line-height: 1.65; }
.dlg-note:empty { display: none; }

/* The actions sit on their own ground, which separates the decision from the
   text without a hairline rule that would cut the tile in half. */
.dlg-actions {
    display: flex; gap: .6rem; justify-content: flex-end;
    padding: 1rem 1.6rem; background: var(--ink-050);
    border-top: 1px solid var(--ink-200);
}
.dlg-actions .btn { min-width: 7rem; justify-content: center; }
/* `.btn` sets `display: inline-flex`, and a class selector beats the browser's
   own `[hidden] { display: none }` -- so hiding the cancel button on an alert
   did nothing and the box offered a choice where there was none. */
.dlg-actions .btn[hidden] { display: none; }

/* A destructive confirmation is marked as one in three places, not only the
   button: the icon, its tint, and the button. Colour alone is invisible to a
   red-green colourblind reader, and this is the button that deletes a branch. */
dialog.dlg.is-danger .dlg-ico { background: var(--bad-050); color: var(--bad-600); }
dialog.dlg.is-alert  .dlg-ico { background: var(--info-050); color: var(--info-600); }

/* ---------------------------------------------------------------- the brand
   Here rather than in site.css because the application and sign-in layouts use
   the same mark and do not load that sheet — the mark rendered unstyled in the
   sidebar for exactly that reason.

   The logo is a dark figure on a transparent ground, so it needs a light tile
   under it: dropped straight onto the navy sidebar it disappears. */
.brand { display: inline-flex; align-items: center; gap: .6rem; font-weight: 800; font-size: 1.3rem; color: var(--brand-900); }
.brand:hover { color: var(--brand-900); }
.brand-mark {
    width: 38px; height: 38px; border-radius: 11px; flex: 0 0 auto;
    background: #fff; padding: 3px;
    display: grid; place-items: center; overflow: hidden;
}
.brand-mark img { width: 100%; height: 100%; object-fit: contain; }

/* ---------------------------------------------------------------- item variants */
/* Picking which options to generate from. Each attribute is a group, and the
   options inside it are targets big enough to hit without aiming — this screen
   is used with a list of sizes in one hand. */
.attr-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 1rem; }
.attr-group {
    border: 1px solid var(--ink-200); border-radius: var(--radius-sm);
    padding: .7rem .85rem .85rem; margin: 0; background: var(--surface);
}
.attr-group legend {
    font-weight: 700; font-size: .86rem; padding: 0 .4rem; color: var(--ink-700);
}
.attr-option {
    display: flex; align-items: center; gap: .5rem;
    padding: .4rem .5rem; border-radius: 6px; cursor: pointer;
    font-size: .92rem; transition: background .12s;
}
.attr-option:hover { background: var(--ink-050); }
.attr-option input { margin: 0; }
/* The price this option adds, pushed to the far edge and set apart: it is a
   consequence of the choice, not part of the option's name. */
.attr-option em {
    margin-inline-start: auto; font-style: normal; font-size: .8rem;
    color: var(--brand-700); font-weight: 700; font-variant-numeric: tabular-nums;
}
.attr-option:has(input:checked) { background: var(--gold-050); }

.attr-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 1rem; }

/* Column headings over a set of repeating form rows. A placeholder vanishes as
   soon as a value is typed, so a row of identical number boxes stops saying
   what its columns are the moment it is filled in — which is exactly when
   somebody comes back to check it. */
.row-heads {
    font-size: .78rem; font-weight: 700; color: var(--ink-500);
    padding: 0 .1rem .35rem; margin-bottom: .2rem;
    border-bottom: 1px solid var(--ink-100);
}

/* ---------------------------------------------------------------- option chips */
/* Defining what an item varies by. The values of one option are entered as
   chips — type, Enter, type — because the version before this took one value per
   page reload: seven round trips to set up a shirt in three sizes and two
   colours, on a screen you had to visit before you could begin. */
.option {
    border: 1px solid var(--ink-200); border-radius: var(--radius-sm);
    padding: .7rem .8rem .8rem; margin-bottom: .7rem; background: var(--surface);
}
.option-head { display: flex; gap: .5rem; align-items: center; margin-bottom: .55rem; }
.option-head .option-name { font-weight: 700; flex: 1; max-width: 22rem; }

.chips {
    display: flex; flex-wrap: wrap; gap: .4rem; align-items: center;
    min-height: 2.4rem; padding: .35rem; border-radius: 8px;
    background: var(--ink-050); border: 1px dashed var(--ink-200);
}
.chips:focus-within { border-color: var(--gold-500); border-style: solid; background: var(--surface); }

.chip {
    display: inline-flex; align-items: center; gap: .3rem;
    background: var(--surface); border: 1px solid var(--ink-200); border-radius: 999px;
    padding: .2rem .3rem .2rem .7rem; font-size: .88rem; font-weight: 600;
}
.chip-label { unicode-bidi: plaintext; }
/* The price this value adds, editable on the chip itself: it belongs to the
   value, and a separate column for it would mean a table where a tag field
   should be. Borderless until touched, so a row of chips reads as words rather
   than as a form. */
.chip-delta {
    width: 4rem; border: 0; background: transparent; text-align: center;
    font: inherit; font-size: .8rem; font-weight: 700; color: var(--brand-700);
    font-variant-numeric: tabular-nums; padding: .1rem .2rem; border-radius: 5px;
}
.chip-delta:hover  { background: var(--ink-050); }
.chip-delta:focus  { background: var(--gold-050); outline: 1px solid var(--gold-500); }
.chip-x {
    border: 0; background: none; cursor: pointer; color: var(--ink-400);
    font-size: 1rem; line-height: 1; padding: .15rem .3rem; border-radius: 50%;
}
.chip-x:hover { background: var(--bad-050); color: var(--bad-600); }

.chip-input {
    border: 0; background: transparent; font: inherit; font-size: .9rem;
    padding: .3rem .4rem; min-width: 11rem; flex: 1;
}
.chip-input:focus { outline: none; }

/* What is about to be created, before it is. A subscriber choosing four sizes
   and five colours is about to make twenty items, and being told so first is the
   difference between a catalogue and a mess. */
.variant-preview {
    margin-top: .9rem; padding: .75rem .85rem; border-radius: var(--radius-sm);
    background: var(--gold-050); border: 1px solid var(--gold-200);
}
.vp-count { font-size: .9rem; margin-bottom: .5rem; color: var(--ink-700); }
.vp-count strong { font-size: 1.3rem; color: var(--brand-800); font-variant-numeric: tabular-nums; }
.vp-list { display: flex; flex-wrap: wrap; gap: .35rem; }
.vp-chip {
    background: var(--surface); border: 1px solid var(--gold-200); border-radius: 999px;
    padding: .15rem .6rem; font-size: .8rem; color: var(--ink-700);
}
.vp-more { font-size: .8rem; color: var(--ink-500); align-self: center; font-weight: 700; }
/* The delta placeholder is a hint, not a value: dim enough that a chip with no
   price difference reads as a word and the one with +25 reads as a number. */
.chip-delta::placeholder { color: var(--ink-300); font-weight: 400; }

/* ---------------------------------------------------------------- variant rows */
/* Six rows of identical grey boxes is a spreadsheet with the gridlines removed:
   nothing says which row you are on, and the thing that identifies it — the
   combination — reads the same weight as the barcode nobody has filled in yet.
   So the combination leads, as badges, and the code is a quiet second line. */
/* One line: the combination, then the code. Stacked they were eighty pixels a
   row, and a shop with four sizes and five colours has twenty of them. */
.vrow-name { min-width: 18rem; white-space: nowrap; }
.vrow-name > * { vertical-align: middle; }
.vrow-part {
    display: inline-block;
    background: var(--ink-050); border: 1px solid var(--ink-200); border-radius: 999px;
    padding: .05rem .5rem; font-size: .8rem; font-weight: 700; color: var(--ink-700);
    margin-inline-end: .25rem;
}
/* The editable fields stay editable but stop shouting: a border only where the
   cursor is, so a table of six reads as rows rather than as thirty boxes. */
.vrow-code, .vrow-barcode, .vrow-price {
    border-color: transparent; background: transparent;
}
.vrow-code:hover, .vrow-barcode:hover, .vrow-price:hover,
.vrow-code:focus, .vrow-barcode:focus, .vrow-price:focus {
    border-color: var(--ink-200); background: var(--surface);
}
.vrow-code    { width: 9.5rem; font-size: .78rem; color: var(--ink-400); padding-block: .15rem; }
/* A placeholder alone reads as a label rather than as something you can type
   into, so an empty barcode keeps a faint outline to say it is a field. */
.vrow-barcode { width: 9.5rem; border-color: var(--ink-100); padding-block: .2rem; }
.vrow-price   { width: 6rem; font-weight: 800; color: var(--brand-800); padding-block: .2rem; }
.vrow-none    { color: var(--ink-300); }
.vrow-price:read-only, .vrow-code:read-only, .vrow-barcode:read-only { cursor: default; }
.vrow-have { font-weight: 700; color: var(--ok-600); }

/* A row that edits itself: the fields sit on one line inside the cell so the
   table still reads as a table rather than as a stack of forms. */
.line-edit { display: flex; gap: .3rem; align-items: center; margin: 0; }

/* A two-way choice that decides what the rest of a form means. Segmented rather
   than a dropdown because there are two answers, the choice changes the fields
   underneath it, and both options should be readable without opening anything. */
.seg { display: inline-flex; border: 1px solid var(--ink-200); border-radius: 10px; overflow: hidden; }
.seg-opt { margin: 0; }
.seg-opt input { position: absolute; opacity: 0; pointer-events: none; }
.seg-opt span {
    display: inline-flex; align-items: center; gap: .4rem; cursor: pointer;
    padding: .55rem 1.1rem; font-size: .92rem; font-weight: 600; color: var(--ink-500);
    background: var(--surface); transition: .12s;
}
.seg-opt + .seg-opt span { border-inline-start: 1px solid var(--ink-200); }
.seg-opt span:hover { background: var(--ink-050); }
.seg-opt input:checked + span { background: var(--brand-700); color: #fff; }
.seg-opt input:focus-visible + span { outline: 2px solid var(--gold-500); outline-offset: -2px; }

/* The attributes an item already varies by, with a real detach on each. Set
   apart from the chip groups below because removing one deletes the variants
   built on it — not something to do by pressing a small × next to a word. */
.attached { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin-bottom: .85rem; }
.attached-one {
    display: inline-flex; align-items: center; gap: .4rem;
    background: var(--ink-050); border: 1px solid var(--ink-200); border-radius: 999px;
    padding: .2rem .5rem .2rem .8rem; font-size: .85rem; font-weight: 700; color: var(--ink-700);
}
.attached-one a { color: var(--ink-400); display: inline-flex; padding: .1rem; border-radius: 50%; }
.attached-one a:hover { background: var(--bad-050); color: var(--bad-600); }

/* ---------------------------------------------------------------- attribute values */
/* Three short columns for two or three rows do not need a table: the thead, the
   borders and the cell padding cost more room than the values do, and the card
   ends up mostly chrome. A light header line and a grid say the same thing. */
.attr-cards { align-items: start; }
.attr-card { display: flex; flex-direction: column; }
.attr-card .card-body { flex: 1; }
.pt-0 { padding-top: 0 !important; }

.vlist-head, .vlist-row {
    display: grid; grid-template-columns: 1fr 5.5rem 3rem 1.6rem;
    gap: .5rem; align-items: center;
}
.vlist-head {
    font-size: .75rem; font-weight: 700; color: var(--ink-400);
    padding-bottom: .3rem; margin-bottom: .35rem; border-bottom: 1px solid var(--ink-100);
}
.vlist-row + .vlist-row { margin-top: .35rem; }
/* Borderless until touched, so a column of values reads as words rather than as
   a stack of empty boxes. */
.vlist-row .input { border-color: transparent; background: transparent; }
.vlist-row .input:hover, .vlist-row .input:focus {
    border-color: var(--ink-200); background: var(--surface);
}
.vlist-used { font-size: .78rem; color: var(--ink-400); font-variant-numeric: tabular-nums; white-space: nowrap; }
.vlist-x a { color: var(--ink-300); display: inline-flex; padding: .2rem; border-radius: 50%; }
.vlist-x a:hover { background: var(--bad-050); color: var(--bad-600); }

.attr-foot {
    display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
    padding: .7rem 1.1rem; border-top: 1px solid var(--ink-100); background: var(--ink-050);
}

/* ---------------------------------------------------------------- categories */
/* A name, a count and a way to remove it. A full table for three short columns
   is more chrome than content, and a card wrapped round a single text box is a
   card doing nothing. */
.pb-0 { padding-bottom: 0 !important; }
.cat-list { display: flex; flex-direction: column; }
.cat-row {
    display: flex; align-items: center; gap: .7rem;
    padding: .6rem .2rem; border-bottom: 1px solid var(--ink-100);
}
.cat-row:last-child { border-bottom: 0; }
.cat-name { font-weight: 700; flex: 1; }
.cat-count {
    display: inline-flex; align-items: center; gap: .3rem;
    font-size: .82rem; font-weight: 700; color: var(--brand-700);
    background: var(--ink-050); border-radius: 999px; padding: .15rem .6rem;
    font-variant-numeric: tabular-nums;
}
.cat-count:hover { background: var(--gold-050); }
/* An empty category is a fact, not a link: nothing to open. */
.cat-count.empty-count { color: var(--ink-400); font-weight: 400; background: transparent; }
.cat-x { color: var(--ink-300); display: inline-flex; padding: .25rem; border-radius: 50%; }
.cat-x:hover { background: var(--bad-050); color: var(--bad-600); }
/* The variants table is a list you edit, so its rows are list-height rather than
   form-height: the inputs lose their own padding and the cells carry it. */
table.data td:has(.vrow-price), table.data td:has(.vrow-barcode), table.data td:has(.vrow-code) { padding-block: .35rem; }

/* The values a chosen attribute already has, one click away. Outlined rather
   than filled, so they read as "available" beside the chips that are chosen —
   and retyping «كبير» exactly is the step that creates a second size with a
   trailing space that looks identical on every screen. */
.suggest { display: flex; flex-wrap: wrap; gap: .35rem; margin-bottom: .5rem; }
.suggest-one {
    display: inline-flex; align-items: center; gap: .2rem;
    border: 1px dashed var(--ink-300); background: transparent; cursor: pointer;
    border-radius: 999px; padding: .18rem .6rem .18rem .45rem;
    font: inherit; font-size: .82rem; color: var(--ink-500);
}
.suggest-one:hover { border-style: solid; border-color: var(--gold-500); background: var(--gold-050); color: var(--ink-700); }
.suggest-one i { font-size: .9rem; }
.option-head .option-name { flex: 1; max-width: 22rem; font-weight: 700; }
.option-head .option-typed { flex: 1; max-width: 22rem; font-weight: 700; }

/* ---------------------------------------------------------------- detail rows */
/* A label and its value, on one line, used by the employee, lead and deal files.
   It had no rule at all, so the two ran together — «الأساسي6000.00» — on three
   screens whose whole job is to be read. A class that exists in the markup and
   nowhere in the stylesheet looks like a typo until you grep for it. */
.detail {
    display: flex; align-items: baseline; gap: .75rem;
    padding: .45rem 0; border-bottom: 1px solid var(--ink-100);
}
.detail:last-child { border-bottom: 0; }
.detail > span { color: var(--ink-500); font-size: .88rem; }
/* The value is pushed to the far end and is the thing being read, so it carries
   the weight. Logical, so it lands on the left in Arabic and the right in
   English without being written twice. */
.detail > b, .detail > strong {
    margin-inline-start: auto; font-weight: 700; unicode-bidi: plaintext;
}

/* ---------------------------------------------------------------- party file */
/* One panel that reads down, not three frames side by side. Three equal boxes
   holding a single chip, four rows and one big number are three-quarters empty
   by definition — the grid makes them the same height and only one of them has
   that much to say. */
.party-panel {
    background: var(--surface); border: 1px solid var(--ink-200);
    border-radius: var(--radius); overflow: hidden; position: relative;
}
/* Which way the balance points, in colour: «عليه» and «له» is what anybody
   opens this page to find out, and a minus sign is not enough. */
.party-panel::before {
    content: ''; position: absolute; inset-block: 0; inset-inline-start: 0; width: 4px;
    background: var(--ink-200);
}
.party-panel.owing::before  { background: var(--warn-600); }
.party-panel.credit::before { background: var(--ok-600); }

.pp-balance {
    display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap;
    padding: 1rem 1.3rem .85rem;
}
.pp-label  { font-size: .9rem; color: var(--ink-500); font-weight: 700; }
.pp-figure {
    font-size: 2.1rem; font-weight: 800; color: var(--brand-800);
    font-variant-numeric: tabular-nums; line-height: 1;
}
.party-panel.owing .pp-figure { color: var(--warn-700); }
.pp-cur   { font-size: .85rem; color: var(--ink-500); }
.pp-clear { font-size: .8rem; color: var(--ok-600); font-weight: 700; margin-inline-start: auto; }

/* One line, not four framed rows: sold, collected, how many and when are read
   together, and a border round each made four sentences out of one. */
.pp-facts {
    display: flex; flex-wrap: wrap; gap: .35rem 1.4rem;
    padding: .7rem 1.3rem; border-top: 1px solid var(--ink-100);
    background: var(--ink-050); font-size: .86rem; color: var(--ink-500);
}
.pp-facts b { color: var(--ink-700); font-weight: 700; unicode-bidi: plaintext; margin-inline-start: .3rem; }

.pp-contact {
    display: flex; flex-wrap: wrap; gap: .4rem .6rem;
    padding: .7rem 1.3rem; border-top: 1px solid var(--ink-100);
}
.pc-row {
    display: inline-flex; align-items: center; gap: .4rem;
    font-size: .85rem; background: var(--ink-050); border-radius: 999px; padding: .2rem .7rem;
}
.pc-row i { color: var(--ink-400); }
.pc-row span { unicode-bidi: plaintext; }
/* The running balance is the column the eye follows down a statement. */
table.data.statement td { padding-block: .55rem; }
table.data.statement .running { font-weight: 800; color: var(--brand-800); }
table.data.statement .dash { color: var(--ink-300); }
.nowrap { white-space: nowrap; }

/* Tabs instead of five stacked cards of near-identical tables: scrolling past
   four to reach the one being looked for, with nothing on the way saying which
   was which. */
/* `justify-content` said here because the card head it shares a box with sets
   space-between for a title and its actions, and that spread four tabs from
   one edge of the card to the other — a row of switches reads as a set only
   while they are next to each other. */
.doc-tabs { display: flex; justify-content: flex-start; gap: .3rem; flex-wrap: wrap; padding-block: .5rem; }
.doc-tab {
    display: inline-flex; align-items: center; gap: .4rem; cursor: pointer;
    /* A flat chip rather than bare text: an unselected tab that carries no
       surface of its own reads as a caption, and nobody clicks a caption. */
    border: 1px solid var(--ink-100); background: var(--ink-050); border-radius: 8px;
    padding: .45rem .85rem; font: inherit; font-size: .9rem; font-weight: 600; color: var(--ink-500);
    transition: background .12s, color .12s, border-color .12s;
}
.doc-tab:hover { background: var(--ink-100); color: var(--ink-700); }
.doc-tab.on {
    background: var(--brand-700); color: #fff; border-color: var(--brand-700);
}
.doc-tab.on .badge { background: rgba(255,255,255,.22); color: #fff; }
/* A statement is read forwards and its point is the last line, so the panel is
   capped and opens scrolled to the end rather than pushing everything below it
   off the screen. The closing figure is the big one at the top of the page, so
   nothing has to be scrolled to to read the balance. */
.statement-wrap { max-height: 22rem; overflow-y: auto; }
/* The row being scrolled past is clipped mid-glyph under the heading, which
   reads as broken text unless something says it is passing underneath. */
.statement-wrap thead th {
    position: sticky; top: 0; background: var(--surface); z-index: 1;
    box-shadow: 0 1px 0 var(--ink-100), 0 5px 6px -5px rgba(15, 23, 42, .25);
}
