/*
 * One stylesheet, cached after the first page.
 *
 * The look is the Central Bank portal's, deliberately. People move between
 * the two all day: they read a contract there and reconcile it here, and a
 * second visual language to learn is a second chance to misread a figure.
 * Colours, radii, the sidebar, the state pills and the table are measured
 * from screenshots of the portal itself rather than guessed at.
 *
 * One downloaded font: Almarai, which Mouad asked for on 13 September. It is
 * a Libyan-legible Arabic face and it does what the system stack cannot —
 * look the same on the manager's Mac, the clerk's Windows machine and the
 * phone in between.
 *
 * The reasoning that kept webfonts out until now has not gone away, so the
 * cost is paid down rather than ignored: `display=swap` renders every word in
 * the system stack on the first paint and swaps when Almarai arrives, a
 * `preconnect` starts the handshake with the font host before the CSS asks
 * for it, and the system stack is still the fallback — if the font never
 * loads the screen is the one we had last week, not an empty one.
 *
 * **It is served from this system, not from Google.** Six woff2 files, 151 KB
 * in total, sitting in `web/static/web/fonts/` beside this stylesheet. A link
 * to Google would have meant every screen in every Libyan office waiting on a
 * handshake with somebody else's server before a word could change shape —
 * the wrong dependency for a system that has to work on a bad morning, and
 * one more thing to be blocked or slow. Almarai is under the SIL Open Font
 * License, which permits exactly this; the licence travels with the files.
 *
 * Each face is declared with a `unicode-range`, so an Arabic page fetches the
 * Arabic file and the Latin one only because the figures are Latin digits —
 * 49 KB for the weight the whole screen is set in — and the heavier weights
 * arrive only where something is actually bold.
 *
 * One theme, light, for the same reason. The portal has no dark mode, and a
 * dark copy of it would not look like it.
 */


/* ---------- Almarai ----------
 *
 * Served from here rather than from a font host; see the note at the top.
 * Three weights, because that is what the interface uses once the browser has
 * matched: 400 for text, 700 for anything the design asks for 600 or 650 —
 * Almarai has no 600, and CSS weight matching picks 700 for it rather than
 * smearing the 400 into a synthetic bold — and 800 for the headline figures.
 */
@font-face {
  font-family: Almarai;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/almarai-arabic-400-normal.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1, U+08E3-08FF, U+FB50-FDFF, U+FE70-FEFF, U+10E60-10E7E, U+1EE00-1EEFF;
}
@font-face {
  font-family: Almarai;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/almarai-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: Almarai;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/almarai-arabic-700-normal.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1, U+08E3-08FF, U+FB50-FDFF, U+FE70-FEFF, U+10E60-10E7E, U+1EE00-1EEFF;
}
@font-face {
  font-family: Almarai;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/almarai-latin-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: Almarai;
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("fonts/almarai-arabic-800-normal.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1, U+08E3-08FF, U+FB50-FDFF, U+FE70-FEFF, U+10E60-10E7E, U+1EE00-1EEFF;
}
@font-face {
  font-family: Almarai;
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("fonts/almarai-latin-800-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* How far a field's box sits below the top of the field: its label's
     line (.95rem at line-height 1.55) and the .35rem gap under it. A button
     beside a field moves down by this much to stand on the box's line. */
  --label-row: calc(.95rem * 1.55 + .35rem);
  /* The same for the labels over a filter's boxes (.range, .filters). */
  --range-label-row: calc(.9rem * 1.55 + .2rem);

  /* ---------------------------------------------------------------------
     The Central Bank's own portal, matched.

     Mouad, 14 Sep, with the address: https://fx.cbl.gov.ly/ — "make it
     similar to this."

     The reason is not decoration. The people who use this system spend part
     of every morning in that portal, downloading the export this system
     reads. Two screens about the same money, an hour apart, should not look
     like two different trades. So the values below are that portal's, taken
     off the page rather than guessed at: it is built on Tailwind, so the
     greys are Tailwind's grey scale and the green is green-600, and the
     corner it rounds every box and button by is 6px.

     Its typeface is Almarai, which is already what this system uses.
     --------------------------------------------------------------------- */

  /* Del, 16 October 2026, from his screenshot of the portal's «الرئيسية»
     (7 October), the colours read off its pixels: a warmer grey ground,
     softer card edges, a calmer green for the chosen menu item and an
     orange-red sign-out. Its buttons are not in that picture, so the
     button green below stays the one measured on 14 September. */
  --ground:      #F7F7F6;   /* the portal's page */
  --surface:     #FFFFFF;
  --surface-2:   #F7F7F6;
  --border:      #EEEDEC;   /* the portal's card edge */
  --frame-line:  #E5E7EB;   /* gray-200, the portal's side panel edge */
  --menu-text:   #3A4150;   /* the portal's menu words */
  --menu-on:     #437C41;   /* its chosen menu item: words */
  --menu-on-icon:#559E50;   /*                       icon */
  --menu-on-bg:  #F3FCF4;   /*                       ground */
  --signout:     #C4442E;   /* its «تسجيل الخروج» */
  --signout-soft:#FDF3F1;
  --border-firm: #D1D5DB;   /* gray-300 — what the portal draws a field in */
  --ink:         #111827;   /* gray-900 */
  --ink-2:       #4B5563;   /* gray-600 */
  --ink-3:       #6B7280;   /* gray-500 */

  --accent:      #16A34A;   /* green-600, the portal's button */
  /* The same green one step darker, for green that is *text*. White on
     green-600, and green-600 on white, both measure 3.30:1 — under the 4.5
     the guidelines ask of body text, and a bank's name in a table at 13.6px
     is body text. green-700 measures 5.02:1 and, side by side, reads as the
     same green. Fills stay green-600, so the system still looks like the
     portal; only the letters are darkened. Measured 14 Sep, every visible
     run of text on every screen. */
  --accent-text: #15803D;
  --accent-2:    #15803D;   /* green-700 */
  --accent-deep: #166534;   /* green-800 */
  --accent-soft: #F0FDF4;   /* green-50  */
  --accent-line: #BBF7D0;   /* green-200 */
  --brass:       #B45309;   /* amber-700 — the bank-balance half of a bar */

  --good:        #15803D;   /* green-700 */
  --warn:        #D97706;   /* amber-600 */
  --warn-soft:   #FFFBEB;   /* amber-50  */
  --crit:        #DC2626;   /* red-600   */
  --crit-soft:   #FEF2F2;   /* red-50    */
  --info:        #2563EB;   /* blue-600  */

  /* Tailwind's shadow-sm, which is what the portal puts under a raised box:
     barely there, and the same under everything. */
  --shadow: 0 1px 2px 0 rgba(0,0,0,.05);
  --shadow-card: 0 1px 2px 0 rgba(0,0,0,.05);
  --radius: 6px;
  --radius-sm: 6px;
  --side: 17.5rem;

  /* Almarai, at Mouad's request, 13 Sep: "use the almaraai font" — and, as it
     turned out the next day, the portal's own typeface too.
     The system stack behind it is not decoration: `font-display: swap` draws
     every word in it on the first paint and changes to Almarai when the file
     arrives, so a slow morning costs a font and never a blank screen. */
  --sans: Almarai, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent-text); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

.num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* Arabic customer names sit beside Latin references; let each run render in
   its own direction rather than forcing one on both. */
.bidi { unicode-bidi: plaintext; }

/* ---------- sign in ---------- */

/* Plain white, like the portal's own sign-in. The green wash that used to be
   here was the one place in the system with a colour behind the words, and
   the portal has nothing of the kind: a mark, a heading, two fields, a green
   button. */
.signin-page {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 2rem 1.25rem;
  background: var(--surface);
}

.signin {
  width: 100%;
  max-width: 23rem;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.signin-brand { display: flex; flex-direction: column; gap: .4rem; text-align: center; }
.signin-mark {
  align-self: center;
  width: 2.9rem; height: 2.9rem;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  margin-bottom: .35rem;
}
.glyph { display: block; }
/* The portal sets its heading at 24px and 700, with the line underneath it in
   grey — a good deal larger than this was, and it is the first thing anybody
   reads in the morning. */
.two-step-qr { display: flex; justify-content: center; margin: 0 auto 1rem; }
.two-step-qr svg { width: 200px; height: 200px; background: #fff; padding: 6px; border-radius: 8px; }
.two-step-key { font-family: ui-monospace, monospace; font-size: 1rem; letter-spacing: .05em; text-align: center; margin: 0 0 .5rem; overflow-wrap: anywhere; }
.door-lang { margin: .8rem 0 0; display: flex; justify-content: center; }
.door-actions { display: flex; gap: .6rem; justify-content: center; flex-wrap: wrap; }
.door-actions .door-lang { margin: 0; }
.two-step-copy { text-align: center; margin: 0 0 1rem; }
/* On a phone the QR code is on the phone itself: a link that opens the
   authenticator app instead (Del, 10 October 2026). Nothing to open it with
   on a computer, so it is drawn only on a touch screen or a narrow one. */
.two-step-app { display: none; text-align: center; margin: 0 0 1rem; }
@media (pointer: coarse), (max-width: 40rem) { .two-step-app { display: block; } }
.signin-logo { width: 64px; height: 64px; object-fit: contain; margin: 0 auto .2rem; border-radius: 12px; }
.signin-brand h1 { font-size: 1.5rem; font-weight: 800; margin: 0; letter-spacing: -.01em; }
.signin-brand p { margin: 0; color: var(--ink-3); font-size: .9rem; }

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

/* No card round the sign-in fields. The portal puts them straight on the
   page, and a white card on a white page is a border drawn for no reason. */
.signin .card { border: 0; box-shadow: none; background: none; }
.signin form { padding: 0; display: flex; flex-direction: column; gap: 1.25rem; }
.signin .btn { width: 100%; justify-content: center; margin-top: .25rem; }

/* A field, as the portal draws one: the label above it in the text colour
   rather than a grey, the box white with a grey-300 hairline, 8px by 12px of
   padding inside, and the corner rounded by 6. Focus is a 2px green line laid
   just inside the edge — it does not push the box about, and it is the same
   green as the button, so the eye learns one colour for "this is live". */
.field { display: flex; flex-direction: column; gap: .35rem; }
.field label { font-size: .95rem; font-weight: 400; color: #374151; }   /* the portal's: regular, dark grey */
.field input {
  font: inherit;
  padding: .5rem .75rem;
  min-height: 2.625rem;          /* 42px, the portal's field */
  border: 1px solid var(--border-firm);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
}
.field input:focus {
  border-color: var(--accent);
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  box-shadow: none;
}

.btn {
  font: inherit;
  /* Almarai is drawn at 300, 400, 700 and 800 — there is no 600 in it, so a
     600 here is the browser picking 700 and pretending otherwise. Said
     plainly instead. */
  font-weight: 700;
  font-size: .9375rem;
  line-height: 1.25;
  padding: .5rem 1.15rem;
  min-height: 2.625rem;          /* 42px, the height of the field beside it */
  display: inline-flex; align-items: center; justify-content: center;
  gap: .45rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.btn:hover { background: var(--accent-2); color: #fff; }
.btn:active { background: var(--accent-deep); }
.btn[disabled], .btn[aria-busy="true"] { opacity: .65; cursor: progress; }
/* The portal's second button: white, a grey-300 hairline, grey-700 words.
   `.btn.ghost` is the same button under an older name, so it is drawn
   exactly the same rather than as a third grey. */
.btn-quiet, .btn.ghost {
  background: var(--surface);
  color: #374151;                /* gray-700 */
  border-color: var(--border-firm);
}
.btn-quiet:hover, .btn.ghost:hover {
  background: var(--surface-2); color: var(--ink); border-color: var(--border-firm);
}
.btn-quiet:active, .btn.ghost:active { background: var(--border); }
/* Backing out — «إلغاء», «رجوع», «مسح», «مسح الفلتر» — is plain dark words
   beside the green button, with no box, as on the portal's own forms and
   filters (Del, 16 October 2026). Still a button's height, so a row lines up. */
.btn.btn-text {
  background: none; border-color: transparent; box-shadow: none;
  color: var(--ink); padding-inline: .6rem;
}
.btn.btn-text:hover { background: none; color: var(--ink-2); text-decoration: underline; }
.btn.btn-text:active { background: none; }

/* The button that applies a filter, at the end of a row of boxes.

   It used to be `btn-quiet` with the padding and font size shrunk by an inline
   style, which made it the same pale rectangle as the reset link next to it
   and smaller than the fields it belonged to. Two identical grey buttons, and
   nothing saying which one was the action. */
/* Same height as every other button and every field (it used to be 44px
   beside 35px boxes, so the row never lined up); only a little wider, so it
   still reads as the action. */
.btn-apply { padding-inline: 1.6rem; }
.btn-reset { padding-inline: 1.1rem; }

.form-error {
  background: var(--crit-soft);
  border: 1px solid var(--crit);
  border-radius: var(--radius);
  padding: .6rem .75rem;
  font-size: .85rem;
  color: var(--crit);
}

/*
 * Not a refusal — a fact. "You were signed out because your account was
 * opened on another device" is the system explaining itself, and red would
 * tell the reader they had done something wrong when they had not. Blue,
 * which this palette uses nowhere else for text, so it cannot be mistaken
 * for either the error above it or the green that means a thing worked.
 */
.form-note {
  background: #EFF6FF;                 /* blue-50 */
  border: 1px solid #BFDBFE;           /* blue-200 */
  border-radius: var(--radius);
  padding: .6rem .75rem;
  font-size: .85rem;
  color: #1D4ED8;                      /* blue-700 — 6.31:1 on blue-50 */
  margin-bottom: .75rem;
}

/*
 * A question, not a refusal: the typed figure disagrees with the one the
 * Central Bank published, and the person has to say which they mean. Amber
 * rather than red, because nothing has gone wrong.
 */
.confirm {
  background: var(--warn-soft);
  border: 1px solid var(--warn);
  border-radius: var(--radius);
  padding: .8rem .9rem;
  display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
}
.confirm p {
  margin: 0 0 .2rem; flex-basis: 100%;
  font-size: .85rem; line-height: 1.55; color: var(--ink-2);
}
.btn-warn { background: var(--warn); color: #fff; }
/* The portal's red, for declining a request: «رفض الطلب», «إرسال الرفض». */
.btn.btn-danger { background: var(--crit); color: #fff; }
.btn.btn-danger:hover { background: #B91C1C; color: #fff; }
.btn.btn-danger:active { background: #991B1B; }
.btn-warn:hover, .btn-warn:active { background: #8C5215; }
.crit-text { color: var(--crit); }

.signin-foot { text-align: center; font-size: .78rem; color: var(--ink-3); }

/* ---------- shell ---------- */

/*
 * The portal's frame: a fixed panel on the reading side holding the mark, the
 * navigation and the person signed in, and beside it a white bar carrying the
 * name of the page. `inset-inline-start` puts the panel on the right in Arabic
 * and on the left in English without a second rule.
 */

body.app { padding-inline-start: var(--side); min-height: 100vh; }

.side {
  position: fixed;
  inset-block: 0;
  inset-inline-start: 0;
  width: var(--side);
  background: var(--surface);
  border-inline-end: 1px solid var(--frame-line);
  display: flex;
  flex-direction: column;
  z-index: 20;
  overflow-y: auto;
}

.side-mark {
  display: flex; align-items: center; gap: .6rem;
  padding: 1.15rem 1.35rem;
  text-decoration: none; color: var(--ink);
  border-bottom: 1px solid var(--border);
}
.side-mark .mark {
  width: 1.9rem; height: 1.9rem; border-radius: 50%; flex: none;
  background: var(--accent-2); color: #fff;
  display: grid; place-items: center;
}
/* A company's own logo sits in the same circle, so the frame does not move
   when one is added. No green behind it: their mark, not ours. */
.side-mark .mark.has-logo { background: var(--surface-2); overflow: hidden; }
.side-mark .mark.has-logo img { width: 100%; height: 100%; object-fit: cover; }

.logo-card { display: flex; align-items: center; gap: 1.25rem; padding: 1rem; flex-wrap: wrap; }
.logo-now {
  width: 5rem; height: 5rem; flex: none; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface-2);
  display: grid; place-items: center; overflow: hidden;
}
.logo-now img { width: 100%; height: 100%; object-fit: contain; }
.logo-none { font-size: .75rem; color: var(--ink-3); }
.logo-say { display: flex; align-items: flex-start; gap: .75rem; flex-wrap: wrap; min-width: 0; }
/* Wraps, so that on a phone «حفظ» goes under the file box instead of off the
   edge of the screen. Found 1 October at 360, 375, 393 and 412px; seen on
   Del's Redmi A5 on 2 October, the button half off the left of the screen and
   the whole page sliding sideways. */
.logo-form { display: flex; align-items: flex-start; gap: .6rem; flex-wrap: wrap; min-width: 0; }
/* «حفظ» and «إزالته» on the line of «اختر ملفًا», not at the foot of the hint. */
.logo-form > .btn { margin-top: var(--label-row); }
/* On a phone the button wraps under the field instead: no gap above it. */
@media (max-width: 46rem) { .logo-form > .btn { margin-top: 0; } }
.logo-form .field { min-width: 0; max-width: 100%; }
.logo-form input[type="file"] { max-width: 100%; }
.side-mark .wordmark { display: flex; flex-direction: column; line-height: 1.15; }
.side-mark .wordmark b { font-size: .9rem; font-weight: 650; letter-spacing: -.01em; }
.side-mark .wordmark span { font-size: .68rem; color: var(--ink-3); letter-spacing: .02em; }

.side nav { display: flex; flex-direction: column; gap: .1rem; padding: .8rem .7rem; }
.side nav a {
  display: flex; align-items: center; gap: .7rem;
  padding: .6rem .75rem;
  border-radius: var(--radius-sm);
  color: var(--menu-text); text-decoration: none;
  font-size: .9rem;
}
.side nav a svg { flex: none; color: var(--ink-3); }
/* Every destination carries a long name and a short one. This is the laptop,
   so the long one — the portal's own wording — is the one that shows. */
.side nav a .short { display: none; }
.side nav a:hover { background: var(--surface-2); color: var(--ink); }
.side nav a.here { background: var(--menu-on-bg); color: var(--menu-on); font-weight: 600; }
.side nav a.here svg { color: var(--menu-on-icon); }

.side-foot { margin-top: auto; border-top: 1px solid var(--border); padding: .9rem .8rem; }
.side-who { display: flex; align-items: center; gap: .7rem; padding: .3rem .55rem .7rem; }
.side-who svg { flex: none; color: var(--ink-3); }
.side-who .lines { min-width: 0; }
.side-who b { display: block; font-size: .85rem; font-weight: 600; }
.side-who span { display: block; font-size: .74rem; color: var(--ink-3);
                 overflow: hidden; text-overflow: ellipsis; }

.side-act { display: flex; align-items: center; gap: .35rem; }
.side-act form { flex: none; }
.side-out {
  display: flex; align-items: center; gap: .6rem;
  width: 100%; font: inherit; font-size: .9375rem; font-weight: 700;
  padding: .55rem .75rem; min-height: 2.625rem; border: 0; border-radius: var(--radius-sm);
  background: none; color: var(--signout); cursor: pointer; text-align: start;
}
.side-out:hover { background: var(--signout-soft); }
.side-lang {
  font: inherit; font-size: .9375rem; font-weight: 700;
  padding: .5rem 1rem; min-height: 2.625rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border-firm); background: var(--surface);
  color: #374151; cursor: pointer;
}
.side-lang:hover { background: var(--surface-2); }

.pagebar {
  background: var(--surface);
  /* No line under it: the portal's title bar casts a soft shadow instead. */
  box-shadow: 0 1px 8px rgba(17, 24, 39, .07);
  padding: .95rem 1.6rem;
  display: flex; align-items: center; gap: 1rem;
  position: sticky; top: 0; z-index: 10;
}
.pagebar h2 { margin: 0; font-size: 1.05rem; font-weight: 650; letter-spacing: -.01em; }
.pagebar .back {
  margin-inline-start: auto;
  width: 2.1rem; height: 2.1rem; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-2);
  text-decoration: none;
}
.pagebar .back:hover { background: var(--surface-2); }
.pagebar .back svg { transform: scaleX(1); }
[dir="ltr"] .pagebar .back svg { transform: scaleX(-1); }

/* ---------- the frame, on a phone ----------
 *
 * Mouad's screenshot, 17 September: everything that is a panel down the side
 * of a laptop had become a block on top of the phone — the wordmark, six
 * links wrapping three-and-three, his name, his number, English, Sign out —
 * and the page itself started below the halfway line. Del, 19 September:
 * "make the side menu looking good in the phone experince."
 *
 * So the panel splits in two on a phone, the way a phone expects:
 *
 *   a slim bar at the top   which company's figures these are, and the two
 *                           buttons that are not destinations — language and
 *                           signing out — as far out of the way as they can
 *                           be while still being findable
 *
 *   a bar at the bottom     the six destinations, icon over a short word,
 *                           where a thumb already is
 *
 * The name and telephone number leave the frame altogether. They were three
 * lines of chrome on every screen to tell somebody something they know, and
 * the account page says it properly.
 *
 * No script and no hamburger. A menu behind a tap is a destination nobody
 * finds, and this system is used by people who are being shown it for the
 * first time over somebody's shoulder.
 */
@media (max-width: 60rem) {
  body.app { padding-inline-start: 0; padding-bottom: 4.4rem; }

  .side {
    position: sticky; inset-block: auto; top: 0; width: auto;
    flex-direction: row; align-items: center; flex-wrap: wrap;
    border-inline-end: 0; border-bottom: 1px solid var(--frame-line);
    overflow: visible;
  }

  .side-mark { flex: 1; min-width: 0; padding: .55rem .9rem; border-bottom: 0; }
  .side-mark .wordmark { min-width: 0; }
  .side-mark .wordmark b,
  .side-mark .wordmark span {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Only a platform administrator sees this, and on a phone it needs the
     whole width rather than a corner of the top bar. */
  .side-company { order: 3; flex: 1 0 100%; border-top: 1px solid var(--border); }

  .side-foot { margin-top: 0; border-top: 0; padding: .45rem .7rem; }
  /* Who you are is on the account screen. Here it was three lines of frame
     on every page to tell somebody their own name. */
  .side-who { display: none; }
  .side-out { width: auto; padding: .5rem .55rem; }
  .side-out .long { display: none; }

  /* The bar along the bottom. */
  .side nav {
    position: fixed; inset-inline: 0; bottom: 0; z-index: 30;
    flex-direction: row; flex-wrap: nowrap; gap: 0;
    padding: .2rem .15rem;
    /* The home bar on a modern phone sits over the bottom of the screen. */
    padding-bottom: calc(.2rem + env(safe-area-inset-bottom, 0px));
    background: var(--surface);
    border-top: 1px solid var(--border);
  }
  /* Each tab as wide as its own word, not seven equal slots. Equal slots
     were 51px apiece on a 360px phone — the width of most Samsung A-series
     and the commonest Android screen — and المستخدمين needs 53, so it came
     out as المستخدمـ… on exactly the phones most people carry. Sharing the
     room by what each word needs fits all seven with space to spare, and the
     floor keeps the shortest one a thumb wide. Tested 30 September at 360,
     375, 393, 412 and 430. */
  .side nav a {
    flex: 1 1 auto; min-width: 2.75rem;
    flex-direction: column; align-items: center; justify-content: center;
    gap: .15rem; padding: .4rem .1rem .3rem;
    font-size: .63rem; line-height: 1.1; text-align: center;
    border-radius: var(--radius-sm);
  }
  .side nav a svg { width: 21px; height: 21px; }
  .side nav a .long { display: none; }
  .side nav a .short {
    display: block; max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* Where you are, said by the colour and the weight rather than by a filled
     pill — six pills in a row is a stripe, not a signal. */
  .side nav a.here { background: none; color: var(--menu-on); font-weight: 650; }
  .side nav a:hover { background: none; }
  .side nav a:active { background: var(--surface-2); }

  /* Eight tabs, which is what a platform administrator has: Companies as
     well as the seven. At the floor above, eight tabs need more than a 360px
     phone has, and the last one — المستخدمين — fell off the edge (Del's
     Redmi A5, 2 October). A slightly lower floor and no side padding fit all
     eight, in both languages, without shrinking the words. */
  .side nav:has(> a:nth-of-type(8)) a { min-width: 2.3rem; padding-inline: 0; }

  /* The page title scrolls with the page on a phone. It was sticky at the
     very top, like the bar above it, so the moment the page moved it slid
     underneath that bar — and for a platform administrator, whose bar also
     carries «تنظر إلى», it was hidden almost at once (Del's screenshot of
     الشركة والمصارف, 2 October). The bar above already says where you are. */
  .pagebar { position: static; }
  /* With the page bar no longer sticking, the red step-in bar sticks to the
     very top instead of a gap's height below it. */
  .step-in-bar { top: 0; }
}

/* On the shortest phones the long name of the system is the first thing that
   can go: the company's own name underneath it is the useful half. */
@media (max-width: 26rem) {
  .side-mark .wordmark b { display: none; }
  .side-mark .wordmark span { font-size: .8rem; color: var(--ink); font-weight: 600; }
}

/* The offer to put the system on the home screen (base.html; phone.js, part
   6, decides whether it shows). A card floating over the foot of the page,
   above the bottom bar, so it covers nothing a person has to reach — and
   "Not now" puts it away for a fortnight. The one shadow in the system that
   is more than a hairline, because it is the one thing that floats. */
.install-offer {
  position: fixed; z-index: 40;
  inset-inline: .6rem; bottom: .6rem;
  max-width: 30rem; margin-inline: auto;
  display: grid; grid-template-columns: auto 1fr; gap: .6rem .75rem;
  align-items: start;
  padding: .9rem .95rem .8rem;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(17, 24, 39, .14);
}
.install-offer img { width: 2.5rem; height: 2.5rem; border-radius: .6rem; }
.install-offer p { margin: 0; font-size: .85rem; line-height: 1.6; color: var(--ink-2); }
.install-offer p + p { margin-top: .3rem; }
.install-offer .install-offer-title {
  font-size: .95rem; font-weight: 700; color: var(--ink); margin-bottom: .1rem;
}
.install-offer-actions {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; gap: .5rem; justify-content: flex-end;
}
@media (max-width: 60rem) {
  /* Above the bottom bar and the phone's home bar under it. */
  body.app .install-offer { bottom: calc(4.6rem + env(safe-area-inset-bottom, 0px)); }
}

/* Where «تثبيت الآن» points when the browser will not let a page install
   itself: the screen dimmed, a white arrow at the browser's own button —
   Chrome's menu at the top, Safari's Share at the bottom — and one line saying
   what to tap there. Physical left and right on purpose: the browser's
   buttons sit where the browser puts them, whichever way the page reads. */
.install-pointer {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(17, 24, 39, .62);
}
.install-pointer-arrow {
  position: absolute; width: 3.25rem; height: 3.25rem; color: #fff;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .35));
}
.install-pointer-say {
  position: absolute; left: 1rem; right: 1rem;
  max-width: 24rem; margin-inline: auto;
  display: flex; flex-direction: column; gap: .8rem; align-items: flex-start;
  padding: 1rem 1.1rem;
  background: var(--surface); color: var(--ink);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(17, 24, 39, .25);
}
.install-pointer-say p { margin: 0; font-size: 1rem; line-height: 1.7; font-weight: 700; }
.install-pointer[data-where="top-right"] .install-pointer-arrow { top: .35rem; right: .6rem; }
.install-pointer[data-where="top-left"] .install-pointer-arrow { top: .35rem; left: .6rem; }
.install-pointer[data-where^="top"] .install-pointer-say { top: 4.4rem; }
.install-pointer[data-where="bottom"] .install-pointer-arrow {
  bottom: calc(.35rem + env(safe-area-inset-bottom, 0px));
  left: 50%; margin-left: -1.625rem; transform: rotate(180deg);
}
.install-pointer[data-where="bottom"] .install-pointer-say {
  bottom: calc(4.4rem + env(safe-area-inset-bottom, 0px));
}

/* The mark of the test copy (TEST_SITE in config/settings.py). An amber strip
   at the top of every page, in the test icon's own amber, and an amber line
   along the top of the frame so that a page scrolled past the strip still
   says which copy it is. Never drawn on the real system. */
.test-strip {
  background: var(--brass); color: #fff;
  text-align: center; font-size: .82rem; font-weight: 700;
  padding: .35rem 1rem;
  letter-spacing: .01em;
}
body.test-site .side { border-top: 3px solid var(--brass); }

/* The platform administrator acting for a company (accounts/step_in.py). Red,
   and sticky under the page bar, so that a page scrolled down still says
   whose name his changes go in under. */
.step-in-bar {
  background: var(--crit); color: #fff;
  display: flex; align-items: center; justify-content: center; gap: 1rem;
  flex-wrap: wrap;
  padding: .45rem 1rem; font-size: .85rem; font-weight: 650;
  position: sticky; top: 3.2rem; z-index: 9;
}
.step-in-bar form { margin: 0; }
.step-in-bar button {
  background: #fff; color: var(--crit); border: 0; border-radius: 999px;
  padding: .25rem .8rem; font: inherit; font-weight: 700; cursor: pointer;
}
.settings-head .step-in-offer { margin-top: 1rem; margin-bottom: 0; }
.settings-head .step-in-offer form { margin: 0; }

.wrap { max-width: 80rem; margin: 0 auto; padding: 1.4rem 1.6rem 4rem; }

.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: 1.25rem;
}
.page-head h1 { font-size: 1.35rem; margin: 0 0 .15rem; letter-spacing: -.015em; }
.page-head .sub { color: var(--ink-3); font-size: .85rem; margin: 0; }
.page-head .sub.viewing {
  color: var(--warn); font-weight: 600; margin-bottom: .1rem;
}

.range { display: flex; align-items: flex-end; gap: .5rem; flex-wrap: wrap; }
.range .field { gap: .2rem; }
.range label { font-size: .9rem; color: #374151; }
.range input, .range select { font: inherit; font-size: .9rem; padding: .5rem .75rem;
  min-height: 2.625rem;
  border: 1px solid var(--border-firm); border-radius: var(--radius);
  background: var(--surface); color: var(--ink); }

section { margin-bottom: 1.75rem; }
/* The heading of the last-ten panel carries a way through to the whole
   record, so the panel is a door rather than a dead end. */
.moves-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.moves-head a { font-size: .78rem; font-weight: 600; text-transform: none; letter-spacing: 0; white-space: nowrap; }

h2.section {
  font-size: .78rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); margin: 0 0 .6rem; font-weight: 650;
}

/* ---------- alerts ---------- */

.alerts { display: flex; flex-direction: column; gap: .5rem; }
/* No coloured bar down the leading edge — Mouad, 13 Sep: "remove the border
   right on alert" — but the hairline all the way round stays, at his word:
   "keep the border on alert 1px". Severity is carried by the tint of the
   card, the colour of the heading and the ▲ ● ■ before it; the border's job
   is to say where the card ends, which is a different job. */
.alert {
  display: flex; gap: .75rem; align-items: flex-start;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .75rem .9rem;
}
.alert .body { flex: 1; min-width: 0; }
/* On a phone the step-in offer's button goes under its words, which were
   squeezed to a word a line beside it (full test, 15 October 2026). */
@media (max-width: 46rem) {
  .alert.step-in-offer { flex-wrap: wrap; }
  .alert.step-in-offer .body { flex-basis: calc(100% - 2rem); }
}
.alert strong { display: block; font-size: .92rem; }
.alert p { margin: .15rem 0 0; font-size: .85rem; color: var(--ink-2); }
.alert .sig { font-size: .95rem; line-height: 1.3; }
/* The five-minute undo, on the page you land on after uploading. Quieter
   than a warning — nothing is wrong yet — but it has a button in it. */
.undo-line { align-items: center; justify-content: space-between; gap: 1rem; }
.undo-line .body strong { font-size: .9rem; }
.undo-line form { flex: none; }

.alert.critical { background: var(--crit-soft); }
.alert.critical .sig, .alert.critical strong { color: var(--crit); }
.alert.warning { background: var(--warn-soft); }
.alert.warning .sig, .alert.warning strong { color: var(--warn); }
.alert.note .sig { color: var(--info); }
.alert a { font-size: .83rem; font-weight: 600; white-space: nowrap; }

/* ---------- figures ---------- */

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: .75rem; }
.tile {
  /* A figure in millions, as live's are, outgrew its tile at the size meant
     for thousands (Del's screenshot, 16 October 2026: «4,005,309.03» over the
     card's edge). The tile is the measure (`cqi`, a hundredth of its width):
     a figure is never bigger than its tile can hold a fourteen-character one
     at, so the widest live has, «955,973,588.57», fits on a laptop and a phone. */
  container-type: inline-size;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .9rem 1rem;
  display: flex; flex-direction: column; gap: .15rem;
}
.tile .label {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); font-weight: 600;
}
.tile .value { font-size: min(1.5rem, 10cqi); font-weight: 650; letter-spacing: -.02em; line-height: 1.15; }
.tile .unit { font-size: .78rem; color: var(--ink-3); font-weight: 500; }
.tile .foot { font-size: .78rem; color: var(--ink-3); margin-top: .1rem; }
.tile.hero { background: var(--accent-soft); border-color: var(--accent); }
.tile.hero .value { color: var(--accent-text); font-size: min(1.85rem, 13.5cqi); }
.tile.hero .label { color: var(--accent-text); }

/* ---------- the band of figures above a filtered list ---------- */

.band { margin-bottom: 1.6rem; }
.band-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: .5rem 1rem; margin-bottom: .6rem;
}

/* The figures answer a question, and this says which question. Without it a
   filtered total reads as the company's total. */
.applied { margin: 0; display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.chip-filter {
  font-size: .75rem; color: var(--ink-2);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px; padding: .2rem .6rem;
}
.chip-filter bdi { color: var(--ink); font-weight: 650; }
.applied a { font-size: .75rem; color: var(--ink-3); }

/* Bigger than the dashboard's, because here it is the first thing on the
   page rather than one section among several. */
.tiles.headline .tile.hero .value { font-size: min(2.4rem, 13.5cqi); }
.tiles.headline .tile .value { font-size: min(1.7rem, 10.5cqi); }

/* Up to three banks, so boxes rather than a list you have to open. Nothing
   ticked is every bank, which is what an untouched filter should mean. */
.label-as-legend { font-size: .9rem; color: #374151; }
.boxes { display: flex; flex-wrap: wrap; gap: .3rem; }
.box {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .85rem; height: 2.2rem; padding: 0 .6rem;
  border: 1px solid var(--border-firm); border-radius: var(--radius);
  background: var(--surface); cursor: pointer; white-space: nowrap;
}
.box:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-text); font-weight: 650; }
.box input { margin: 0; accent-color: var(--accent); }

/* ---------- tables ---------- */

.table-wrap {
  overflow-x: auto; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
}
table { border-collapse: collapse; width: 100%; font-size: .85rem; }
th, td { padding: .75rem .9rem; text-align: start; border-bottom: 1px solid var(--border); white-space: nowrap; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: var(--surface-2); }
thead th {
  background: var(--surface-2); color: var(--ink-3);
  font-size: .8rem; font-weight: 400;   /* the portal's: regular grey words */
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--surface-2); }
td.n, th.n { text-align: end; font-variant-numeric: tabular-nums; }
td.strong { font-weight: 650; }
.muted { color: var(--ink-3); }
.pos { color: var(--good); }
.neg { color: var(--crit); }
.money { font-variant-numeric: tabular-nums; }

/* a bar drawn in the cell itself — no library, no request */
/*
 * What one request leaves you.
 *
 * The figure leads and the bar follows it, measured against the best-paying
 * bank rather than against a total — so the longest bar is always the bank
 * worth having, and no arithmetic can push one past the end of its track. A
 * bank that lost money gets no bar: a loss is said, in red, not drawn.
 */
.yield { display: flex; align-items: center; gap: .6rem; }
.yield .figure { font-size: 1.05rem; font-weight: 650; min-width: 4.2rem; text-align: end; }
.yield .track {
  flex: 1; min-width: 3rem; height: 8px;
  border-radius: 4px; background: var(--surface-2); overflow: hidden;
}
.yield .track > span { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.yield.down .figure { color: var(--crit); }
.yield.down .track { background: repeating-linear-gradient(
    135deg, var(--crit-soft), var(--crit-soft) 4px, transparent 4px, transparent 8px); }

.bar { display: block; height: 6px; border-radius: 3px; background: var(--surface-2); overflow: hidden; min-width: 4rem; }
.bar > span { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.bar.two > span.b { background: var(--brass); }

/* Two parts of one whole, side by side, so the split is the picture. */
.bar.duo { display: flex; }
.bar.duo > span { border-radius: 0; }
.bar.duo > span.a { background: var(--accent); }
.bar.duo > span.b { background: var(--brass); }
.bar.duo > span:first-child { border-start-start-radius: 3px; border-end-start-radius: 3px; }
.bar.duo > span:last-child { border-start-end-radius: 3px; border-end-end-radius: 3px; }

/* A colour beside a label, so identity is never colour alone. */
.key { display: inline-block; width: .55rem; height: .55rem; border-radius: 2px; margin-inline-end: .35rem; }
.key.a { background: var(--accent); }
.key.b { background: var(--brass); }

.pair { display: flex; flex-direction: column; gap: 3px; }
.pair .k { font-size: .68rem; color: var(--ink-3); letter-spacing: .04em; text-transform: uppercase; }
/* A count with its share written underneath, inside a numeric cell. Without
   this the flex column left the figure at the start of the cell while every
   other number in the table hugged the column's edge, and a column of figures
   that does not line up is harder to read down. */
td.n .pair { align-items: start; }

/* Whose figures you are looking at, in the frame, for a platform
   administrator. It sits directly under the mark because that is where the
   answer to "where am I" belongs, and because on every screen but the
   dashboard there used to be no answer and no way to change it. */
.side-company {
  display: flex; flex-direction: column; gap: .3rem;
  padding: .9rem 1rem 0;
}
.side-company label {
  font-size: .68rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3);
}
.side-company select {
  font: inherit; font-size: .85rem;
  padding: .5rem .75rem; min-height: 2.625rem;
  border: 1px solid var(--border-firm); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
  width: 100%;
}
.side-company select:focus {
  border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: -2px;
}

/* The actions at the right of a page heading: an export beside whatever the
   page's own action is. They sit together so neither reads as the other's
   afterthought, and they wrap under the heading on a phone. */
.head-actions { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; }

/* ---------- tabs ----------
 *
 * Mouad, 14 Sep: "i feel its very random at الشركة والمصارف / make taps up for
 * banks." One bank, one panel, chosen from a row of tabs — so the same bank
 * stops appearing three times in three places down four metres of page.
 *
 * Drawn the way the portal draws a tab strip: no boxes, no pills, a single
 * hairline along the bottom of the row with the chosen tab's own line sitting
 * on top of it in green. The line is a border rather than a background,
 * because a filled tab competes with the buttons underneath it, and on this
 * page the buttons are the things that do something.
 *
 * Links, not script: the choice is in the address, so it survives a save, a
 * reload, the back button and a link somebody sends.
 */
.tabs {
  display: flex; flex-wrap: wrap; gap: .25rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 1.25rem;
}
.tabs .tab {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .65rem .9rem;
  min-height: 2.75rem;
  margin-bottom: -1px;               /* sit the tab's line on the row's line */
  border-bottom: 2px solid transparent;
  color: var(--ink-3);
  font-weight: 400; font-size: .95rem;   /* the portal's tabs: regular words, green when chosen */
  text-decoration: none;
  white-space: nowrap;
}
.tabs .tab:hover { color: var(--ink); border-bottom-color: var(--border-firm); }
.tabs .tab.on {
  color: var(--accent-text);
  border-bottom-color: var(--accent);
}
/* The one that adds rather than chooses. Quieter, and pushed to the far end
   so it is never mistaken for one of the banks. */
.tabs .tab.add { color: var(--ink-3); font-weight: 400; margin-inline-start: auto; }
.tabs .tab.add.on { color: var(--accent-text); }
.tabs .tab .chip { font-size: .62rem; padding: .05rem .4rem; }
/* The tabs of الإعدادات (_settings_tabs.html), across the top of the content,
   above the page each one opens. A desk reads the long names, a phone the
   short ones, and on a phone the row wraps onto a second line rather than
   running off the edge (the rule below). */
/* .wrap.settings-head, not .settings-head: the phone's own .wrap padding
   comes later in this file and would otherwise win. */
.wrap.settings-head { padding-bottom: 0; }
.settings-head ~ .wrap { padding-top: 1rem; }
.settings-head .tabs { margin-bottom: 0; }
.settings-tabs .short { display: none; }
@media (max-width: 60rem) {
  .wrap.settings-head { padding-top: .8rem; padding-bottom: 0; }
  .settings-tabs .long { display: none; }
  .settings-tabs .short { display: inline; }
}

/* The Central Bank tab: the token as its last four characters, never more. */
.token-now { display: flex; flex-direction: column; gap: .25rem; margin-bottom: 1rem; }
.token-tail {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.15rem; font-weight: 700; letter-spacing: .04em; color: var(--ink);
}
.token-actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.token-actions form { display: inline-flex; }
.token-actions a.btn { text-decoration: none; display: inline-flex; align-items: center; }
.token-none { color: var(--ink-3); margin: 0 0 .6rem; }
.central-bank .alert.tried { margin-top: 1rem; }
.alert.cbl-switch { margin-bottom: 1.25rem; }
.alert.cbl-switch form { margin: 0; }

/* A bank tab may wrap on a phone. On one line, a long bank name made a single
   tab wider than the screen, and the whole page slid sideways (2 October).
   After the rule above on purpose: the later rule wins. */
@media (max-width: 60rem) {
  .tabs .tab { white-space: normal; overflow-wrap: anywhere; max-width: 100%; }
}

/* The panel behind one tab: what this bank is and how it charges side by
   side, and its balances across the foot of both. `.cols` used to lay these
   out on its own and left a hole where the tallest panel wrapped. */
.bank-grid {
  display: grid; gap: 1rem; align-items: start;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-bottom: 1.5rem;
}
.bank-grid > .wide { grid-column: 1 / -1; }
/* minmax(0, 1fr), not 1fr: a plain 1fr column grows to fit whatever is
   widest inside it, and on a 360px phone that made every bank panel 364px
   and the setup page slide sideways (measured 2 October). */
@media (max-width: 60rem) { .bank-grid { grid-template-columns: minmax(0, 1fr); } }

/* A short list of label-and-value lines inside a panel — how a bank charges,
   what it holds. Plain rows, not a table: there are two of them. */
.mini-list { list-style: none; margin: 0; padding: 0; }

/* A state, written the way the portal writes one: a pale pill, never bare
   coloured text. Green is the resting state there, so green is the default. */
.chip {
  display: inline-block; font-size: .72rem; font-weight: 600;
  padding: .15rem .6rem; border-radius: 999px;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent-2);
  white-space: nowrap;
}
.chip.cash { color: var(--brass); border-color: #EADFC4; background: #FDF8EE; }
.chip.noncash { color: var(--info); border-color: #CFE0EA; background: #F1F7FA; }
.chip.ok { color: var(--accent-2); }
/* red-700 rather than the red-600 everything else uses: the chip is 11.5px on
   a pink ground, where red-600 measures 4.41 and the guidelines want 4.5.
   Nobody would have seen the difference; the measurement did. */
.chip.bad { color: #B91C1C; border-color: #FECACA; background: var(--crit-soft); }
/* Amber-700 on amber-50, for the same reason the red above is red-700: at
   11.5px the amber-600 the rest of the interface uses measures 3.4 against
   this ground, and a state nobody can read is not a state. This one says
   "somebody could sign in as this person" — it has to be legible. */
.chip.warn { color: #B45309; border-color: #FDE68A; background: var(--warn-soft); }
/* From the Central Bank's connection: a request still waiting for the
   company's approval, and one the customer withdrew. Neither is money. */
.chip.wait { color: var(--info); border-color: #CFE0EA; background: #F1F7FA; }
.chip.gone { color: var(--ink-3); border-color: var(--border); background: var(--surface-2); }

/* A button that sits inside a table cell beside a chip: quiet, and small
   enough not to make the row taller than the rows around it. */
/* Del, 16 October 2026: "make all buttons same size". So the one in a
   table row is the same button as everywhere else, only spaced off its chip. */
.btn.small { margin-inline-start: .4rem; }

/* Ordinary ↔ view only, beside the kind in the people table. Inline, like
   the "open it again" button in the password column, so the row stays one
   line high wherever it fits. */
.kind-switch { display: inline; }

.empty {
  background: var(--surface); border: 1px dashed var(--border-firm);
  border-radius: var(--radius); padding: 2rem 1.25rem; text-align: center;
  color: var(--ink-3);
}
.empty strong { display: block; color: var(--ink); margin-bottom: .3rem; }

.split { display: grid; grid-template-columns: 1.6fr 1fr; gap: 1rem; align-items: start; }

/* A grid or flex child does not shrink below its own content unless it is
   told to: its default `min-width` is `auto`, not zero. That is why the
   sideways scroller inside one silently stops scrolling and pushes the whole
   page instead — on a phone the dashboard sat 482px wider than the screen and
   every heading was drawn off the edge, while the scroller it was supposed to
   be inside did nothing. */
.split > *, .cols > *, .stack > * { min-width: 0; }
.table-wrap { min-width: 0; }
@media (max-width: 60rem) { .split { grid-template-columns: 1fr; } }

.note-line { font-size: .8rem; color: var(--ink-3); margin: .5rem 0 0; }

@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }


/* ---------- upload, front and centre ---------- */

.upload-lead {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: 1rem;
  align-items: start;
  margin-bottom: 2rem;
}
@media (max-width: 62rem) { .upload-lead { grid-template-columns: 1fr; } }

.upload-card { padding: 1.4rem 1.5rem; border-color: var(--border-firm); }
.upload-head h1 { font-size: 1.3rem; margin: 0 0 .25rem; letter-spacing: -.015em; }
.upload-head p { margin: 0 0 1.1rem; color: var(--ink-2); font-size: .9rem; }

@media (max-width: 48rem) { .upload-grid { grid-template-columns: 1fr; } }

.upload-grid select, .upload-grid input[type=file] {
  font: inherit; font-size: .9rem; width: 100%;
  padding: .5rem .75rem; min-height: 2.625rem;
  border: 1px solid var(--border-firm); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
}
.upload-grid input[type=file] { padding: .45rem .5rem; }
.upload-grid button { white-space: nowrap; }

.upload-note {
  margin: 1rem 0 0; font-size: .8rem; color: var(--ink-3);
  border-top: 1px dashed var(--border-firm); padding-top: .7rem;
}
.field-error { margin: .25rem 0 0; font-size: .8rem; color: var(--crit); font-weight: 600; }

.upload-history h2.section { margin-top: 0; }
.feed { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; }
.feed li {
  display: flex; align-items: center; gap: .6rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .5rem .7rem; font-size: .82rem;
}
.feed-when { color: var(--ink-3); font-size: .74rem; white-space: nowrap; }
.feed-what { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.feed-what .k { font-size: .7rem; }


.mono { font-family: var(--mono); font-size: .78rem; }
.warn-text { color: var(--warn); }
.crumb { margin: 0 0 .2rem; font-size: .8rem; color: var(--ink-3); }
.crumb a { color: var(--ink-3); }


tfoot tr.total td { background: var(--surface-2); border-top: 2px solid var(--border-firm); }

.inline-form { display: flex; gap: .6rem; align-items: end; flex-wrap: wrap; }
.inline-form .field { flex: 1 1 8rem; }
.inline-form input {
  font: inherit; font-size: .9rem; width: 100%;
  padding: .5rem .75rem; min-height: 2.625rem; border: 1px solid var(--border-firm);
  border-radius: var(--radius); background: var(--surface); color: var(--ink);
}

.mini-row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: .5rem; padding: .35rem 0; border-bottom: 1px solid var(--border);
  font-size: .87rem;
}
.mini-row:last-of-type { border-bottom: none; }


/* ---------- forms beyond sign-in ---------- */

.field .hint { font-size: .76rem; color: var(--ink-3); line-height: 1.4; }
.field .field-error { font-size: .78rem; color: var(--crit); font-weight: 600; }
.field.has-error input, .field.has-error select { border-color: var(--crit); }
.field select, .field textarea {
  font: inherit; padding: .5rem .75rem;
  min-height: 2.625rem;
  border: 1px solid var(--border-firm); border-radius: var(--radius);
  /* White, like every other box on the portal. These were grey, which read as
     "switched off" next to the white text fields beside them. */
  background: var(--surface); color: var(--ink);
}
.field select:focus, .field textarea:focus {
  border-color: var(--accent); outline: 2px solid var(--accent); outline-offset: -2px;
}
.field input[type="file"] { padding: .5rem; background: var(--surface); }
/* The browser draws a date box a pixel taller than a text box; held to the
   same 42px as the boxes beside it. */
.field input[type="date"], .range input[type="date"] { height: 2.625rem; }
/* The browser's own «اختر ملفًا», where the script has not replaced it, drawn
   as the portal's white button rather than the operating system's grey one. */
input[type="file"]::file-selector-button {
  font: inherit; font-size: .85rem; font-weight: 700;
  padding: .35rem .8rem; margin-inline-end: .6rem;
  border: 1px solid var(--border-firm); border-radius: var(--radius-sm);
  background: var(--surface); color: #374151; cursor: pointer;
}
input[type="file"]::file-selector-button:hover { background: var(--surface-2); }
/* The file box in the system's own words (phone.js, part 7): the browser's
   own box stays in the form, invisible but reachable by keyboard, and a
   button and the chosen file's name stand where it was. */
.file-pick { position: relative; display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; min-width: 0; }
.file-pick .file-pick-input {
  position: absolute; inset: 0; width: 1px; height: 1px;
  opacity: 0; overflow: hidden; pointer-events: none;
}
.file-pick .file-pick-button { flex: none; }
/* It is a <label>, so `.field label` would shrink and darken it; it is a
   button like any other. */
.field .file-pick-button { font-size: .9375rem; font-weight: 700; color: #374151; }
.file-pick:focus-within .file-pick-button { outline: 2px solid var(--accent); outline-offset: 2px; }
.file-pick-name {
  min-width: 0; font-size: .85rem; color: var(--ink-3);
  overflow-wrap: anywhere;
}
.field input[type="checkbox"] { width: auto; }
/* A round choice or a tick box is not a 42px field. Given the field's
   height and padding it became a tall block and its words dropped to the
   line below it (the costs page, 16 October 2026). Drawn in the portal's
   green rather than the browser's blue. */
.field input[type="radio"], .field input[type="checkbox"] {
  min-height: 0; padding: 0; margin: 0; flex: none;
}
input[type="radio"], input[type="checkbox"] { accent-color: var(--accent); }
.field label:has(> input[type="radio"]), .field label:has(> input[type="checkbox"]) {
  display: inline-flex; align-items: center; gap: .55rem;
  font-weight: 400; font-size: .9375rem; min-height: 2.25rem;
}

.alert.good { background: var(--accent-soft); }
.alert.good .sig, .alert.good strong { color: var(--good); }

/* The upload panel — the reason people open this page, so it looks like it. */
.upload-panel {
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.25rem 1.35rem;
  margin-bottom: 1.75rem;
}
.upload-panel h2 {
  margin: 0 0 .2rem; font-size: 1.05rem; letter-spacing: -.01em;
  display: flex; align-items: center; gap: .5rem;
}
.upload-panel h2 .mark {
  width: 1.4rem; height: 1.4rem; border-radius: 50%;
  background: var(--accent); color: #fff;
  display: grid; place-items: center; flex: none;
}
.upload-panel > p { margin: 0 0 1rem; color: var(--ink-3); font-size: .85rem; }
.upload-grid {
  display: grid; grid-template-columns: minmax(14rem, 1.2fr) minmax(14rem, 1.4fr) auto;
  gap: 1rem; align-items: start;
}
/* `> .btn`: only the form's own button. «اختر ملفًا» is a .btn too, and the
   wider rule pushed it down below the line of «رفع» (Del, 16 October 2026:
   "same function button should be in same line"). */
.upload-grid > .btn { margin-top: var(--label-row); white-space: nowrap; }
@media (max-width: 52rem) {
  .upload-grid { grid-template-columns: 1fr; }
  .upload-grid > .btn { margin-top: 0; }
}

/* ---------- one box you type into and pick out of ----------
   The contract on the upload panel. The <select> is still the real control
   and is still in the page; the script hides it and puts .combo-box in front.
   Without the script `.combo-on` is never set, nothing here applies, and the
   dropdown looks as it always did. */

.field[data-combo] { position: relative; }
.field.combo-on > select { display: none; }

.combo-box {
  font: inherit; font-size: .9rem; width: 100%;
  padding: .5rem .75rem; min-height: 2.625rem;
  border: 1px solid var(--border-firm); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
}
.combo-box:focus {
  border-color: var(--accent);
  outline: 2px solid var(--accent); outline-offset: 0;
  background: var(--surface);
}

.combo-list {
  position: absolute; z-index: 40;
  inset-inline-start: 0; inset-inline-end: 0; top: 100%;
  margin: .25rem 0 0; padding: .25rem;
  list-style: none;
  max-height: 16rem; overflow-y: auto; -webkit-overflow-scrolling: touch;
  background: var(--surface);
  border: 1px solid var(--border-firm); border-radius: var(--radius);
  box-shadow: 0 4px 12px -2px rgba(0,0,0,.12), var(--shadow);
}
.combo-option {
  padding: .5rem .55rem; border-radius: 4px;
  font-size: .85rem; line-height: 1.35; cursor: pointer;
}
.combo-option:hover { background: var(--ground); }
.combo-option.on {
  background: var(--accent-soft); color: var(--accent-deep); font-weight: 600;
}
.combo-empty { padding: .6rem .55rem; font-size: .82rem; color: var(--ink-3); }

/* Said to a screen reader, shown to nobody. */
.combo-say {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* A finger is not a mouse pointer. */
@media (max-width: 52rem) {
  .combo-option { padding: .7rem .6rem; font-size: .88rem; }
  .combo-list { max-height: 14rem; }
}

/* ---------- filters, one row above the table ---------- */

.filters {
  display: flex; gap: .5rem; align-items: flex-end; flex-wrap: wrap;
  margin-bottom: .75rem;
}
.filters .field { gap: .2rem; align-self: flex-end; }
.filters label { font-size: .9rem; color: #374151; }
/* input[type=...] rather than a bare element selector, so nothing later
   quietly outranks these and stretches a control to the row's height. */
.filters input[type=search],
.filters input[type=date],
.filters input[type=text],
.filters select {
  font: inherit; font-size: .9rem; padding: .5rem .75rem;
  border: 1px solid var(--border-firm); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
  flex: 0 0 auto; height: 2.625rem;
}
.filters .grow { flex: 1 1 14rem; }
.filters .grow input[type=search] { width: 100%; }

.pager {
  display: flex; justify-content: space-between; align-items: center;
  gap: 1rem; margin-top: .75rem; font-size: .85rem; color: var(--ink-3);
}
.pager .links { display: flex; gap: .4rem; }
.pager a, .pager span.current {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.625rem; height: 2.625rem; padding: 0 .6rem;
  border-radius: var(--radius); background: var(--surface);
  border: 1px solid var(--border-firm); text-decoration: none; color: #374151;
  font-weight: 700;
}
.pager span.current { background: var(--accent); color: #fff; border-color: var(--accent); }
.pager a:hover { background: var(--surface-2); }
/* The gap between the first pages and the last. No border and no box: it is
   not somewhere you can go, and dressing it like the numbers beside it invites
   a click that does nothing. */
.pager .gap { padding: .3rem .2rem; color: var(--ink-3); }
/* Four thousand pages is a long row on a narrow screen. Let it wrap rather
   than push the count off the side. */
.pager .links { flex-wrap: wrap; }

/* A section the page has switched off. Some panels are laid out with
   flex, which would otherwise win against the attribute. */
[hidden] { display: none !important; }

/* phone.js appends this cell to every wide row. On a laptop it is an
   invented fourteenth column and must never be drawn; the phone block below
   switches it on. Hidden here rather than only added on a phone, because a
   window dragged from narrow to wide would otherwise keep it. */
td.more-cell { display: none; }

.panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1.2rem 1.3rem;
  box-shadow: var(--shadow-card);
}
.panel h3 { margin: 0 0 .2rem; font-size: 1rem; }
.panel > p.lead { margin: 0 0 1rem; color: var(--ink-3); font-size: .85rem; }
.panel form { display: flex; flex-direction: column; gap: .8rem; }
.panel form .btn { align-self: flex-start; }

.stack { display: flex; flex-direction: column; gap: 1rem; }
/* Its button at the start of the line, as in every other form, not the
   width of the page («حفظ العقد», 16 October 2026). */
.stack > .btn { align-self: flex-start; }
/* A form whose file box is followed by its button (a bank statement): the
   button beside «اختر ملفًا», on its line, rather than on a line of its own. */
.stack:has(> .field .file-pick) {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 1rem; align-items: start;
}
.stack:has(> .field .file-pick) > * { grid-column: 1 / -1; }
.stack:has(> .field .file-pick) > .field:has(.file-pick) { grid-column: 1; }
.stack:has(> .field .file-pick) > .field:has(.file-pick) + .btn {
  grid-column: 2; margin-top: var(--label-row);
}
/* Never asks for more than the room it has: a 20rem column inside a panel on
   a 360px phone (284px to work with) spilled 36px past the panel's edge —
   the date and amount of a balance, the dates of a statement. On a wider
   screen this is exactly the 20rem it always was. */
.cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); gap: 1rem; align-items: start; }

.row-actions a { font-size: .8rem; font-weight: 600; text-decoration: none; }

/* A button that has to sit beside a link and not look like a second kind of
   thing. Switching a bank off is a change to stored data, so it is a POST and
   therefore a button, whatever it looks like. */
.linklike {
  font: inherit; font-size: .8rem; font-weight: 600;
  background: none; border: 0; padding: 0;
  color: var(--accent-text); cursor: pointer;
}
.linklike:hover { text-decoration: underline; }
.row-actions form { margin-inline-start: .6rem; }
.row-actions a + a { margin-inline-start: .6rem; }

/* Removal sits under a rule at the foot of the edit panel: reachable on
   purpose, never on the way to something else. */
.panel-foot {
  margin-top: 1rem; padding-top: .8rem;
  border-top: 1px solid var(--border);
  display: flex; flex-wrap: wrap; gap: .5rem; align-items: baseline;
}
.panel-foot form { display: flex; gap: .5rem; align-items: baseline; flex-wrap: wrap; }
.linklike.danger { color: var(--crit); }


/* ---------- the phone ----------
 *
 * A company owner checks the day's profit standing in the office, on a phone,
 * not sitting at the laptop where the file was uploaded. Below this width the
 * layout stops pretending to be a smaller laptop.
 *
 * The breakpoint is 46rem and it is also written in phone.js, which cannot ask
 * a stylesheet what its own breakpoints are. Change one, change the other.
 */

@media (max-width: 46rem) {

  .wrap { padding: 1rem 1rem 3rem; }
  .page-head { flex-direction: column; align-items: flex-start; gap: .6rem; }

  /* A table with no headings to borrow — see phone.js. It cannot be labelled,
     but it can be allowed to wrap, and that alone stops it dragging the whole
     page sideways. The dashboard's payment-mix table is the one that did. */
  table[data-wrap] th, table[data-wrap] td { white-space: normal; }

  /* Each row becomes a card, each figure carries its column heading. */
  table.as-cards,
  table.as-cards tbody,
  table.as-cards tr,
  table.as-cards td { display: block; width: auto; }

  table.as-cards thead { display: none; }

  table.as-cards tr {
    padding: .55rem .9rem;
    border-bottom: 1px solid var(--border);
  }
  table.as-cards tr:last-child { border-bottom: 0; }
  table.as-cards tbody tr:hover { background: transparent; }

  table.as-cards td {
    display: grid;
    grid-template-columns: minmax(5.5rem, 38%) 1fr;
    gap: .75rem;
    align-items: baseline;
    padding: .28rem 0;
    border: 0;
    white-space: normal;
  }

  table.as-cards td::before {
    content: attr(data-label);
    color: var(--ink-3);
    font-size: .68rem; text-transform: uppercase; letter-spacing: .05em;
    font-weight: 650; line-height: 1.5;
  }

  /* The column was the alignment; the label is now. A number pushed to the
     far edge of a narrow card is further from its own heading than from the
     one below it. */
  table.as-cards td.n { text-align: start; }

  /* Marked by phone.js: a heading with nothing under it is six lines of
     labels against six dashes. */
  table.as-cards td[data-empty] { display: none; }

  /* A row that spans the width is a summary or an empty-state line, not a
     record — no heading belongs beside it. */
  table.as-cards td[data-span] { grid-template-columns: none; }
  table.as-cards td[data-span]::before { content: none; }

  /* Anything you have to hit with a thumb. 2.75rem is 44px, which is the
     smallest target Apple and Google both consider reliable; several of these
     were 15px, which is a target you miss and then mistrust. */
  table.as-cards td a,
  .row-actions a,
  .moves-head a,
  .pager a, .pager span.current {
    display: inline-flex; align-items: center;
    min-height: 2.75rem; padding-inline: .2rem;
  }
  .side nav a { min-height: 2.75rem; display: flex; align-items: center; }

  /* One control per line, full width, thumb-sized. A row of five small boxes
     that wraps unpredictably is worse than a short column of five clear ones. */
  .filters { flex-direction: column; align-items: stretch; gap: .6rem; }
  .filters .field { width: 100%; align-self: stretch; }
  /* `.grow` is `flex: 1 1 14rem`, which grows along the main axis — and the
     main axis is now the vertical one. Left alone it made the search box
     fourteen rems TALL, with a hand's width of empty white under it. */
  .filters .grow { flex: 0 0 auto; }
  .boxes { flex-direction: column; align-items: stretch; }
  /* A bank's name may break anywhere rather than push the page sideways —
     the same reason as the bank tabs (2 October). */
  .box { min-height: 2.75rem; justify-content: flex-start; min-width: 0; white-space: normal; overflow-wrap: anywhere; }
  .filters input[type=search],
  .filters input[type=date],
  .filters input[type=text],
  .filters select { width: 100%; height: 2.75rem; font-size: 1rem; }
  .filters .btn { width: 100%; min-height: 2.75rem; justify-content: center; }

  /* iOS zooms the whole page in when a focused field is under 16px, and then
     leaves it zoomed. Every typing target is held at 1rem for that reason. */
  input, select, textarea { font-size: 1rem; }
  /* The same for the boxes whose own rule sets a smaller size and so
     outranked the line above: the dashboard's dates, the queue's search,
     the platform administrator's company. */
  .range input, .range select, .combo-box, .upload-grid select,
  .inline-form input, .side-company select { font-size: 1rem; }
  /* And a form's own boxes, whose `.field` rules outranked both lines: at
     15px an iPhone zoomed in on every one of them, and at 42px they stood
     shorter than the 44px buttons under them. */
  .field input:not([type=checkbox]):not([type=radio]):not([type=file]),
  .field select, .field textarea, .range input, .range select,
  .side-company select, .combo-box { font-size: 1rem; min-height: 2.75rem; }
  .field input[type="date"], .range input[type="date"] { height: 2.75rem; }
  .side-lang, .side-out { min-height: 2.75rem; }

  .pager { flex-direction: column; align-items: stretch; gap: .6rem; }
  .pager .links { justify-content: center; }

  /* Everything a thumb has to land on, not only the things inside a table.
     The sign-out button was 39px, the language switch 36, the date fields 38,
     and a link out of a section 15 — all of them targets you miss once and
     then stop trusting. Checkboxes and radios are left alone: the browser
     draws those at a fixed size and stretching the box moves the tick away
     from the label it belongs to. */
  .btn, button { min-height: 2.75rem; }
  input:not([type=checkbox]):not([type=radio]):not([type=file]),
  select, textarea { min-height: 2.75rem; }
  /* A link a thumb is meant to hit gets the same 44px as a button. `.feed-row`
     is here because of the checklist on the welcome screen: its "do this step"
     link was 15px tall on a phone — the one link on that page whose whole job
     is to be pressed. Found on 14 Sep by measuring every link on every screen
     at 390px rather than by looking at them. */
  .note-line a, .alert a, .feed-row a {
    display: inline-flex; align-items: center; min-height: 2.75rem;
  }

  /* The date range above the dashboard, one control to a line like the
     filters below it. */
  .range { flex-direction: column; align-items: stretch; width: 100%; }
  .range .field, .range .btn { width: 100%; }
  .range .btn { justify-content: center; }

  /* The fields behind the tap. Held out of the document rather than merely
     made transparent, so a card is short until somebody asks for the rest. */
  table.as-cards.has-extra td[data-extra] { display: none; }
  table.as-cards.has-extra tr[data-open] td[data-extra] { display: grid; }

  table.as-cards td.more-cell {
    display: block;
    grid-template-columns: none;
    padding: .1rem 0 0;
  }
  table.as-cards td.more-cell::before { content: none; }

  .more-btn {
    font: inherit; font-size: .78rem; font-weight: 650;
    color: var(--accent-text); background: none; border: 0;
    padding: .6rem .1rem; min-height: 2.75rem;
    cursor: pointer; text-align: start;
  }
  .more-btn:hover { text-decoration: underline; }

  /* The opened part sits under a rule so it reads as the same record
     continued, not as the next one starting. */
  tr[data-open] td[data-extra]:first-of-type { border-top: 1px solid var(--border); padding-top: .5rem; }
}

/* A bank's commission arrangements, one per line, each with its first day. */
.commission-line { display: block; }
/* «يرجى الانتظار بينما نجهّز ملفك»: under the page head while a spreadsheet is built. */
.file-wait { margin: 0 0 1rem; padding: .6rem .9rem; border-radius: 8px; background: #EFF6FF; border: 1px solid #BFDBFE; }

/* The language button by the door: its own size, not the width of the card.
   The sign-in card's `.signin form` (a column, stretching what it holds)
   reaches this form too, and stretched the button the width of the card
   whatever its own width said: so the form is laid out as a centred row. */
.door-lang .btn { width: auto; padding-inline: 1.4rem; }
.signin form.door-lang { flex-direction: row; justify-content: center; align-items: center; gap: 0; }

/* A request's reference in a list: the way to its own page. Quiet, as the
   reference it is, and plainly a link on hover. */
.ref-link { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--border-firm); }
.ref-link:hover { color: var(--accent-text); border-bottom-color: var(--accent-text); }

/* ---------- one request on its own page (web/request_detail.html) ----------
 *
 * The portal's «تفاصيل الطلب» (Del, 16 October 2026): a white card of pairs,
 * each a grey label over its value with a hairline under it, two to a row on
 * a computer and one on a phone; beside it, the figures and the contract.
 */
.detail-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem 1rem; flex-wrap: wrap; margin: 0 0 1.1rem;
}
.detail-back { color: var(--ink); font-weight: 700; text-decoration: none; }
.detail-back:hover { text-decoration: underline; }
.detail-actions { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; }
.detail-actions form { margin: 0; }
.detail-grid {
  display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  gap: 1.25rem; align-items: start;
}
.detail-side { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
.detail-card { padding: .5rem 1.6rem 1rem; min-width: 0; margin: 0; }
.detail-card h3 { margin: 1rem 0 .1rem; font-size: 1.1rem; }
.detail-card .lead { margin: 0 0 .3rem; color: var(--ink-3); font-size: .88rem; }
.pairs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 2rem; margin: 0; }
.pairs.one { grid-template-columns: minmax(0, 1fr); }
.pair { padding: 1rem 0; border-bottom: 1px solid var(--border); min-width: 0; }
.pair.wide { grid-column: 1 / -1; }
.pair dt { color: var(--ink-3); font-size: .88rem; margin: 0 0 .35rem; }
.pair dd { margin: 0; font-size: 1rem; color: var(--ink); overflow-wrap: anywhere; }
.pair.net dd { color: var(--accent-text); font-weight: 800; font-size: 1.35rem; }
.pair-note { display: block; margin-top: .3rem; color: var(--ink-2); font-size: .9rem; }
.detail-link { display: inline-block; margin: 1rem 0 .4rem; font-weight: 700; }
.detail-narrow { max-width: 46rem; }
.detail-buttons { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
@media (max-width: 60rem) { .detail-grid { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 40rem) {
  .pairs { grid-template-columns: minmax(0, 1fr); }
  .detail-card { padding: .4rem 1.1rem .8rem; }
  .detail-actions, .detail-actions form, .detail-actions .btn { width: 100%; }
}
