/*
   The panel is a registry desk, not a dashboard.

   The operator's job is literally a registrar's: somebody submits papers, you look at the
   papers, you stamp a decision. So the surface is paper, the text is ink, the tables are ruled,
   and a status is a stamp rather than a coloured sweet. None of that changed.

   What changed is the colour. This used to be the daylight side of a deep Tigris teal, with the
   phone app as its night side. The app is blue on white now, and a teal panel beside a blue app
   is two products. So the values below are the app's — theme/brand.dart is where they live —
   read onto paper: the same blue for action, the same amber for waiting, darkened only where a
   screen value is unreadable as text on white.

   Colour carries one meaning each, consistently:
     amber = somebody is waiting on you    blue = you act    red = you refuse

   Note the split this rewrite introduced: --ink used to be both the text colour and the action
   colour, which worked only because they were the same teal. They are not the same thing and
   are now two variables. Text is --ink; anything you press is --action.
*/
:root {
    --paper:  #f5f7fb;   /* the desk — Brand.page */
    --sheet:  #ffffff;   /* a sheet laid on it — Brand.card */
    --ink:    #101a33;   /* Brand.ink */
    --ink-2:  #4a5470;
    --ink-3:  #69718c;   /* Brand.muted */
    --rule:   #e4e9f5;   /* Brand.line */
    --rule-2: #ccd3ec;

    /* THE action colour, straight off the app. */
    --action:      #0a5af9;   /* Brand.blue */
    --action-deep: #0847c6;   /* pressed — Brand.blueDeep */
    --action-wash: #f1f6ff;   /* selected row fill — Brand.blueTint */

    /* State. Darkened from the app's screen values, which are set against a phone at arm's
       length and fail as small text on white: Brand.amber #ffba28 is 1.8:1 here, and a
       registrar reads these all day. */
    --amber:  #a9700c;
    --amber-wash: #fff4da;
    --green:  #0f7a55;
    --red:    #c42b2b;

    --radius: 8px;

    /* Kufi for anything that names something — it is the lettering of a shop sign, which is
       what most of these records are. Naskh-ish sans for reading.

       These are NOT the app's Cairo and IBM Plex Sans Arabic. The panel serves no font files
       and an operator's desktop will have neither, so naming them here would just fall back to
       Segoe UI while claiming otherwise. Worth closing if the panel ever bundles webfonts. */
    --display: "Noto Kufi Arabic", "Segoe UI", Tahoma, sans-serif;
    --body: "Noto Sans Arabic", "Segoe UI", Tahoma, sans-serif;
    /* Phone numbers and plates are compared column against column, so they are tabular. */
    --data: ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;

    color-scheme: light;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--body);
    font-size: 15px;
    line-height: 1.65;
}

a { color: var(--action); text-underline-offset: 3px; }

/* No letter-spacing anywhere on Arabic: it severs the connected letterforms. */
h1, h2, h3 { font-family: var(--display); letter-spacing: 0; margin: 0; font-weight: 700; }
h1 { font-size: 1.7rem; margin-bottom: 1.6rem; }

/* A section heading is a ruled line with a title sitting on it, the way a ledger page is
   divided. The rule does the work that a card border would otherwise do. */
h2 {
    font-size: 1rem;
    font-weight: 700;
    color: var(--ink);
    margin: 2.2rem 0 .9rem;
    padding-bottom: .45rem;
    border-bottom: 1px solid var(--rule-2);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .8rem;
}
h2:first-of-type { margin-top: 0; }

/* The count beside a section title. Amber only when it is a queue with something in it. */
.count { font-family: var(--data); font-size: .9rem; font-weight: 700; color: var(--ink-3); }
.count.waiting { color: var(--amber); }

/* ---- shell ---- */
.shell { display: flex; min-height: 100vh; }

.sidebar {
    width: 216px;
    flex: 0 0 216px;
    background: var(--sheet);
    border-inline-start: 1px solid var(--rule-2);
    padding: 1.6rem 1rem;
    display: flex;
    flex-direction: column;
}

.content { flex: 1; padding: 2.2rem 2.6rem 4rem; max-width: 1080px; }

.brand { margin-bottom: 2.2rem; }
.wordmark { display: block; font-family: var(--display); font-size: 1.5rem; font-weight: 700; color: var(--ink); }
.brand-sub { display: block; font-size: .78rem; color: var(--ink-3); }

.nav-list { list-style: none; margin: 0; padding: 0; flex: 1; }
.nav-list li { margin-bottom: .1rem; }

.nav-list a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    padding: .5rem .7rem;
    border-radius: var(--radius);
    color: var(--ink-2);
    text-decoration: none;
    /* The marker sits in the gutter so the label never shifts when it appears. */
    border-inline-start: 3px solid transparent;
}

.nav-list a:hover { background: var(--paper); color: var(--action); }
.nav-list a.active {
    background: var(--action-wash);
    border-inline-start-color: var(--action);
    color: var(--action);
    font-weight: 700;
}

/* Amber, because a badge here only ever means somebody is waiting. */
.badge {
    background: var(--amber);
    color: #fff;
    font-family: var(--data);
    font-size: .72rem;
    font-weight: 700;
    min-width: 1.35rem;
    text-align: center;
    padding: 0 .35rem;
    border-radius: 999px;
}

.signout { margin-top: 1.5rem; }
.signout button {
    width: 100%;
    background: none;
    border: 1px solid var(--rule-2);
    color: var(--ink-3);
    padding: .45rem;
    border-radius: var(--radius);
    cursor: pointer;
    font: inherit;
}
.signout button:hover { color: var(--action); border-color: var(--action); }

/* ---- login ---- */
.login-shell { min-height: 100vh; display: grid; place-items: center; padding: 1rem; }

.login-card {
    background: var(--sheet);
    border: 1px solid var(--rule-2);
    border-radius: var(--radius);
    /* One heavier edge, like a form with a printed margin down its side. */
    border-inline-start: 4px solid var(--action);
    padding: 2.4rem 2rem;
    width: min(370px, 100%);
    text-align: center;
}

.login-card .wordmark { font-size: 2.2rem; margin-bottom: .1rem; }
.login-sub { color: var(--ink-3); margin: 0 0 1.8rem; font-size: .9rem; }
.login-card .btn-primary { width: 100%; margin-top: .4rem; }
.login-error {
    background: transparent;
    border: 1.5px solid var(--red);
    color: var(--red);
    border-radius: var(--radius);
    padding: .55rem;
    margin: 0 0 1rem;
    font-size: .88rem;
}

/* ---- forms ---- */
.field { display: block; text-align: start; margin-bottom: 1rem; }
.field > span { display: block; font-size: .82rem; color: var(--ink-2); margin-bottom: .3rem; }

input, select, textarea {
    width: 100%;
    background: var(--sheet);
    border: 1px solid var(--rule-2);
    border-radius: var(--radius);
    color: var(--ink);
    padding: .5rem .65rem;
    font: inherit;
}
input:focus, select:focus, textarea:focus { border-color: var(--action); }
input[type="number"], input[dir="ltr"] { font-family: var(--data); }

input:focus-visible, select:focus-visible, textarea:focus-visible,
button:focus-visible, a:focus-visible {
    outline: 2px solid var(--action);
    outline-offset: 2px;
}

.btn-primary, .btn-danger, .btn-quiet {
    border-radius: var(--radius);
    padding: .5rem 1.1rem;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    border: 1.5px solid transparent;
}
/* Blue, not amber: amber means waiting, and pressing this is the opposite of waiting. */
.btn-primary { background: var(--action); color: #fff; border-color: var(--action); }
.btn-primary:hover:not(:disabled) { background: var(--action-deep); border-color: var(--action-deep); }

/* Outlined until hovered. Refusing somebody should take one deliberate beat longer. */
.btn-danger { background: transparent; color: var(--red); border-color: var(--red); }
.btn-danger:hover:not(:disabled) { background: var(--red); color: #fff; }

.btn-quiet { background: transparent; color: var(--ink-2); border-color: var(--rule-2); }
.btn-quiet:hover { color: var(--action); border-color: var(--action); }

button:disabled { opacity: .4; cursor: not-allowed; }

.actions { display: flex; gap: .55rem; flex-wrap: wrap; align-items: center; margin-top: 1rem; }

/* ---- sheets ---- */
.card {
    background: var(--sheet);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: 1.1rem 1.3rem;
    margin-bottom: 1rem;
}

/*
   The slip: one submitted application, laid out the way it arrived. The name of the thing
   being registered leads, because that is what the operator is deciding about; the person and
   their number sit under it; the decision is at the far end within reach.

   This is the panel's one memorable object, so everything else stays quiet.
*/
.slip {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    background: var(--sheet);
    border: 1px solid var(--rule);
    border-inline-start: 3px solid var(--amber);
    border-radius: var(--radius);
    padding: .85rem 1.1rem;
    margin-bottom: .5rem;
}
.slip:hover { border-color: var(--rule-2); border-inline-start-color: var(--amber); }

.slip-title { font-family: var(--display); font-size: 1.1rem; font-weight: 700; line-height: 1.3; }
.slip-meta { color: var(--ink-2); font-size: .88rem; }
.slip-meta .num { font-family: var(--data); }
.slip-side { display: flex; align-items: center; gap: .8rem; }
.slip-docs { font-size: .8rem; color: var(--ink-3); white-space: nowrap; }

/* One line, at the bottom, out of the way. These numbers are context, not work. */
.tally {
    margin-top: 2.6rem;
    padding-top: .8rem;
    border-top: 1px solid var(--rule);
    color: var(--ink-3);
    font-size: .85rem;
    display: flex;
    flex-wrap: wrap;
    gap: .4rem 1.4rem;
}
.tally b { font-family: var(--data); font-weight: 700; color: var(--ink-2); }

/* Kept for the settings preview, where a computed figure genuinely is the content. */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: .8rem; }
.tile { border-inline-start: 2px solid var(--rule-2); padding: .2rem .9rem; }
.tile .figure { font-family: var(--data); font-size: 1.7rem; font-weight: 700; line-height: 1.2; }
.tile .label { color: var(--ink-3); font-size: .8rem; }
.tile.quiet .figure { color: var(--ink-2); font-weight: 400; }

/* ---- ledger ---- */
/* Wide content scrolls inside its own box; the page never scrolls sideways. */
.table-scroll { overflow-x: auto; }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: start; padding: .6rem .6rem; border-bottom: 1px solid var(--rule); }
thead th {
    color: var(--ink-3);
    font-family: var(--body);
    font-weight: 600;
    font-size: .78rem;
    border-bottom: 1.5px solid var(--rule-2);
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--action-wash); }
/* A value that must read left-to-right inside a right-to-left table: a phone number, a time
   range, a coordinate pair. dir="ltr" is what stops "+964 772..." being reordered on screen —
   but it also flips this cell's `start` from the right edge to the left, which parked the phone
   and the working hours a whole column away from every other value on the review page.
   text-align: right puts them back in line. */
td[dir="ltr"] { font-family: var(--data); font-size: .9rem; text-align: right; }

/* The review page lists one record as label/value rows, so its th is a field name rather than
   a column heading. */
tbody th { color: var(--ink-3); font-weight: 600; font-size: .82rem; width: 8.5rem; }

/*
   A stamp, not a pill. The border and the weight do the work; there is no fill and no jaunty
   rotation, because this is a record of a decision and not a sticker.
*/
.pill {
    display: inline-block;
    padding: .02rem .45rem;
    border: 1.5px solid currentColor;
    border-radius: 3px;
    font-size: .74rem;
    font-weight: 700;
    white-space: nowrap;
}
.pill-pending { color: var(--amber); background: var(--amber-wash); }
.pill-approved { color: var(--green); }
.pill-rejected,
.pill-suspended { color: var(--red); }
.pill-new { color: var(--amber); background: var(--amber-wash); }
.pill-read { color: var(--ink-3); }
.pill-resolved { color: var(--green); }

.muted { color: var(--ink-3); }
.empty { color: var(--ink-3); padding: 1.6rem 0; }
.error-text { color: var(--red); }
.ok-text { color: var(--green); }

/* ---- documents ---- */
/* A shopfront, or a driver with their vehicle. This platform does not collect identity cards —
   see VerificationDocument — so what is on screen is a place or a person, and it is shown large
   enough to actually recognise. An approval that cannot see the evidence is not an approval. */
.docs { display: flex; gap: .9rem; flex-wrap: wrap; }
.doc {
    border: 1px solid var(--rule-2);
    border-radius: var(--radius);
    overflow: hidden;
    width: 230px;
    text-decoration: none;
    background: var(--sheet);
}
.doc:hover { border-color: var(--action); }
/* contain, not cover: a cropped identity card can lose the number the operator is checking. */
.doc img { display: block; width: 100%; height: 165px; object-fit: contain; background: var(--paper); }
.doc .doc-kind { padding: .4rem .6rem; font-size: .8rem; color: var(--ink-2); }

@media (max-width: 760px) {
    .shell { flex-direction: column; }
    .sidebar { width: auto; flex: none; border-inline-start: none; border-bottom: 1px solid var(--rule-2); }
    .nav-list { display: flex; flex-wrap: wrap; gap: .3rem; }
    .nav-list a { border-inline-start: none; border-bottom: 3px solid transparent; }
    .nav-list a.active { border-inline-start-color: transparent; border-bottom-color: var(--action); }
    .signout { margin-top: 1rem; }
    .content { padding: 1.4rem 1.1rem 3rem; }
}

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

/* ---- circuit ---- */
#blazor-error-ui {
    display: none;
    position: fixed;
    inset-block-end: 0;
    inset-inline: 0;
    background: var(--red);
    color: #fff;
    padding: .7rem 1.2rem;
    z-index: 1000;
}
#blazor-error-ui .reload { color: #fff; }
#blazor-error-ui .dismiss { cursor: pointer; float: inline-end; }

#components-reconnect-modal {
    border: 1px solid var(--rule-2);
    border-radius: var(--radius);
    background: var(--sheet);
    color: var(--ink);
    font-family: var(--body);
    padding: 1.6rem 2rem;
    text-align: center;
}
#components-reconnect-modal::backdrop { background: rgba(16, 26, 51, .45); }
#components-reconnect-modal button {
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    margin-top: .6rem;
    padding: .45rem 1.1rem;
    border: 1.5px solid var(--action);
    border-radius: var(--radius);
    background: var(--action);
    color: #fff;
}

/* ---- which deployment this is ----

   Two halves with two jobs. The chip names the deployment on BOTH of them, quietly, because
   "which panel is this tab" is a question an operator holds all day and should never have to
   ask out loud. The strip only appears when this is NOT production, because a warning shown
   on the normal case is a warning nobody reads on the day it matters.

   Amber, not red. Nothing is broken on staging — it is doing exactly what it exists to do. Red
   here would be crying wolf against the colour the panel reserves for a refusal. */

.brand-env {
    display: inline-block;
    margin-top: .35rem;
    padding: .1rem .5rem;
    border-radius: 999px;
    font-family: var(--data);
    font-size: .7rem;
    font-weight: 700;
    line-height: 1.5;
}

.brand-env.live { background: var(--action-wash); color: var(--action); }
.brand-env.test { background: var(--amber-wash); color: var(--amber); }

.env-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .1rem .6rem;
    margin-bottom: 1.8rem;
    padding: .7rem 1rem;
    border: 1.5px solid var(--amber);
    /* The one heavy edge the login card and the approval slips already use, so this reads as
       part of the panel rather than as something the browser injected. */
    border-inline-start-width: 5px;
    border-radius: var(--radius);
    background: var(--amber-wash);
    color: var(--amber);
    font-size: .88rem;
}

.env-strip strong { font-family: var(--display); font-size: .95rem; }
.env-strip span { color: var(--ink-2); }
.env-db { font-family: var(--data); font-size: .8rem; color: var(--amber); }

/* The login screen is a full-height centring grid, so anything placed above it would add its
   height on top of 100vh and put a scrollbar on a page that has nothing to scroll. The column
   takes the viewport instead, and the shell centres in whatever the strip leaves. */
.login-page { min-height: 100vh; display: flex; flex-direction: column; }
.login-page .env-strip { margin: 1rem 1rem 0; }
.login-page .login-shell { min-height: 0; flex: 1; }
.login-sub .brand-env { margin: .1rem 0 0 .35rem; vertical-align: middle; }

/* The moderation queue. A grid rather than the table the other catalogue pages use, because
   what the operator is scanning for here is the picture itself — a row of filenames would
   make them click every one to find the thing they came to remove. */
.image-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
    margin-top: 16px;
}

/* Small enough to sit in a table row, large enough to recognise what it is. */
.thumb {
    width: 44px;
    height: 44px;
    object-fit: contain;
    background: #fff;
    border-radius: 6px;
    border: 1px solid var(--rule);
}

/* ---- the property dictionary ---- */

/* A value list, not a table. Values are one or two words each and there are a dozen under a
   property; rows would make «أسود أحمر أزرق» take a screen to say what a line can. */
.chips { display: flex; flex-wrap: wrap; gap: .4rem; margin: .6rem 0; }

.chip {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .2rem .5rem;
    border: 1px solid var(--rule-2);
    border-radius: var(--radius);
    background: var(--paper);
    font-size: .85rem;
}

/* The delete sits inside the chip because it acts on the chip. Quiet until hovered: this is the
   one control here that loses something, and it should take a beat longer to reach. */
.chip-x {
    border: 0;
    background: none;
    color: var(--ink-3);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0 .1rem;
}
.chip-x:hover:not(:disabled) { color: var(--red); }

/* The dot on a colour value. Bordered, because a white swatch on a white sheet is nothing at all. */
.swatch {
    width: .8rem;
    height: .8rem;
    border-radius: 50%;
    border: 1px solid var(--rule-2);
    display: inline-block;
}

/* ---- page head, icons ---- */
/* A page whose main action is creating something: the title on one side, the button on the other,
   where the eye lands after reading the title. */
.page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.page-head h1 { margin: 0; }
.icon {
    width: 16px;
    height: 16px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.btn-icon-label { display: inline-flex; align-items: center; gap: .35rem; }
.btn-small { padding: .2rem .6rem; font-size: .82rem; }
/* A bare glyph: pencil, trash, close. Quiet until it is pointed at. */
.btn-icon {
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius);
    padding: .3rem;
    color: var(--ink-3);
    cursor: pointer;
    line-height: 0;
}
.btn-icon:hover:not(:disabled) { color: var(--action); border-color: var(--rule-2); }
.btn-icon.danger:hover:not(:disabled) { color: var(--red); border-color: var(--red); }

/* ---- dictionary entries ---- */
/* One card per property, two across. A card shows what the property IS; every change is a dialog,
   so nothing on a card is a form. */
.entries {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr));
    align-items: start;
}
.entry {
    background: var(--sheet);
    border: 1px solid var(--rule);
    border-radius: 12px;
    padding: 1rem 1.2rem;
}
.entry.retired { opacity: .6; }
.entry-head { display: flex; align-items: flex-start; justify-content: space-between; gap: .6rem; }
.entry h2 { margin: 0; padding: 0; border: 0; display: block; font-size: 1.05rem; }
.entry-key { font-family: var(--data); font-size: .74rem; color: var(--ink-3); }
.entry-tools { display: flex; align-items: center; gap: .2rem; }
.entry-tags { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; margin: .7rem 0 .4rem; }
.entry-used { margin-inline-start: auto; font-size: .78rem; color: var(--ink-3); }
.entry-used b, .value-uses b { font-family: var(--data); font-weight: 600; }
.entry-empty { margin: .4rem 0 0; font-size: .88rem; }
/* A classification, not a decision — so a quiet fill rather than the stamp a .pill is. */
.tag {
    font-size: .74rem;
    padding: .05rem .5rem;
    border-radius: 4px;
    background: var(--paper);
    color: var(--ink-2);
    white-space: nowrap;
}
.tag-axis { background: var(--action-wash); color: var(--action); font-weight: 600; }
.value-list { list-style: none; margin: 0; padding: 0; }
.value-list li {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .3rem 0;
    border-bottom: 1px solid var(--rule);
    min-height: 2.3rem;
}
.value-list li:last-child { border-bottom: none; }
.value-uses { margin-inline-start: auto; font-size: .78rem; color: var(--ink-3); white-space: nowrap; }
.dot { width: 14px; height: 14px; border-radius: 50%; border: 1px solid var(--rule-2); flex: none; }
.dot-none { border-style: dashed; border-color: var(--ink-3); }

/* ---- dialog ---- */
.dialog-backdrop {
    position: fixed;
    inset: 0;
    z-index: 900;
    background: rgba(16, 26, 51, .45);
    display: grid;
    place-items: center;
    padding: 1rem;
}
.dialog {
    background: var(--sheet);
    border: 1px solid var(--rule-2);
    border-radius: 12px;
    width: min(470px, 100%);
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    padding: 1.1rem 1.4rem 1.2rem;
    box-shadow: 0 18px 48px rgba(16, 26, 51, .22);
}
.dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; }
.dialog-head h3 { font-size: 1.05rem; }
.dialog-lead { font-size: .85rem; margin: 0 0 1rem; }
/* The confirming button at the far end, cancel beside it, anything destructive pushed to the
   other side by .grow so it is never the thing a hurried click lands on. */
.dialog .actions { justify-content: flex-end; margin-top: 1.2rem; }
.dialog .actions .grow { flex: 1; }
.dialog-error, .dialog-note {
    border-radius: var(--radius);
    padding: .5rem .7rem;
    font-size: .88rem;
    margin: 0 0 1rem;
}
.dialog-error { color: var(--red); background: #fdeeee; }
.dialog-note { color: var(--green); background: #e9f6f0; }
.field .hint, .check .hint { display: block; font-size: .76rem; color: var(--ink-3); margin-top: .25rem; line-height: 1.5; }
.req { color: var(--red); font-weight: 700; }
.field-row { display: flex; gap: .7rem; align-items: flex-start; }
.field-row > .field { flex: 1; }
.field-row > .field.narrow { flex: 0 0 7.5rem; }
.check { display: flex; align-items: flex-start; gap: .5rem; margin-bottom: 1rem; cursor: pointer; }
.check input { width: auto; margin-top: .35rem; }
.swatch-none { margin-top: 1.7rem; }
.preview { font-size: .85rem; color: var(--ink-2); margin: -.4rem 0 1rem; }
.preview b { font-family: var(--display); color: var(--ink); }
input[type="color"] { height: 2.6rem; padding: .2rem; cursor: pointer; }
/* Ticking «بلا لون» has to look like it switched the picker off, or the colour still showing in it
   reads as the colour that will be saved. */
input[type="color"]:disabled { opacity: .3; }
/* A key has no break points — [a-z_] only, up to 40 characters — so without these the name column
   cannot shrink below the whole key and pushes the card's buttons out over the next card. */
.entry-title { min-width: 0; flex: 1; }
.entry-title h2, .entry-key { overflow-wrap: anywhere; }
.entry:focus { outline: none; }

/* ---- shared pieces of the card-and-dialog pages ---- */

/* For a dialog that holds a list: values to tick, barcodes, search results, a path in the tree. */
.dialog.wide { width: min(760px, 100%); }

/* A sentence about what just happened, directly under the page head or inside the card that acted —
   never at the top of a long page, where a refusal after a long form is a refusal nobody sees. */
.banner { border-radius: var(--radius); padding: .55rem .8rem; margin: 0 0 1rem; font-size: .9rem; }
.banner-ok { color: var(--green); background: #e9f6f0; }
.banner-error { color: var(--red); background: #fdeeee; }

/* Why a control is switched off, said above it. A disabled control with no reason reads as a bug.
   Paper, not amber: amber means somebody is waiting on you, and nobody is. */
.lock-note {
    display: flex;
    gap: .55rem;
    align-items: flex-start;
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    padding: .6rem .8rem;
    margin: 0 0 1rem;
    font-size: .86rem;
    color: var(--ink-2);
}
.lock-note .icon { margin-top: .25rem; }

/* Where an aisle sits: «مواد غذائية › حلويات». */
.path { color: var(--ink-3); font-size: .8rem; }

.filters { display: flex; flex-wrap: wrap; gap: .7rem; align-items: flex-end; margin-bottom: 1rem; }
.filters .field { margin: 0; flex: 1 1 12rem; }

.pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: .8rem;
    font-size: .85rem;
    color: var(--ink-3);
}
.pager b { font-family: var(--data); color: var(--ink-2); }

/* A page of cards, one under the other: the product page. */
.stack { display: grid; gap: 1rem; align-items: start; }
.entry h3 { font-size: 1rem; }
.entry-body { margin-top: .8rem; }

/* A list of short records on one sheet — brands, shop types. Rows, not cards: each is a name and a
   couple of facts, and a card apiece would spend a screen saying what a line can. */
.row-list {
    list-style: none;
    margin: 0;
    padding: 0;
    background: var(--sheet);
    border: 1px solid var(--rule);
    border-radius: 12px;
}
.row-item {
    display: flex;
    align-items: center;
    gap: .7rem;
    flex-wrap: wrap;
    padding: .6rem 1rem;
    border-bottom: 1px solid var(--rule);
    min-height: 3rem;
}
.row-item:last-child { border-bottom: none; }
.row-item.retired { opacity: .6; }
.row-main { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.row-tools { display: flex; align-items: center; gap: .2rem; margin-inline-start: auto; }
.row-item:focus { outline: none; }
.row-item .banner { flex-basis: 100%; margin: .2rem 0 0; }
.row-item.chosen { background: var(--action-wash); }
.dialog .row-list { max-height: 18rem; overflow-y: auto; margin-bottom: 1rem; }
.entry .banner { margin: .7rem 0 0; }
.field-row > .hint { flex: 1; margin-top: 1.9rem; }

/* The moderation queue's cards. contain, not cover: a cropped photograph can hide the very thing
   the operator is looking for. */
.image-card { display: flex; flex-direction: column; gap: .25rem; }
.image-card-img {
    display: block;
    width: 100%;
    height: 180px;
    object-fit: contain;
    background: #fff;
    border-radius: var(--radius);
}
.image-card-title { margin: .5rem 0 0; }
/* What a confirmation is about, when it is a picture. */
.confirm-thumb {
    display: block;
    max-width: 100%;
    max-height: 200px;
    margin: 0 auto 1rem;
    object-fit: contain;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
}

/* The aisle tree. Each level steps in and hangs from a thin line, so a leaf's branch and root can be
   read off the page without opening anything. */
.tree { list-style: none; margin: 0; padding: 0; }
.tree-children {
    list-style: none;
    margin: 0;
    margin-inline-start: 1.5rem;
    padding: 0;
    padding-inline-start: .6rem;
    border-inline-start: 1px solid var(--rule-2);
}
.tree-row {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .3rem .5rem;
    border-radius: var(--radius);
    min-height: 2.4rem;
}
.tree-row:hover { background: var(--action-wash); }
.tree-row:focus { outline: none; }
.tree-row.retired { opacity: .55; }
.tree-name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.tree-count { font-family: var(--data); font-size: .78rem; color: var(--ink-3); white-space: nowrap; }
.tree li > .banner { margin: .2rem 0 .4rem; }

/* Something that needs doing, not a refusal: amber, the colour of «somebody is waiting on you». */
.tag-warn { background: var(--amber-wash); color: var(--amber); font-weight: 600; }
.banner-warn { color: var(--amber); background: var(--amber-wash); }

/* Shop-type checkboxes in an aisle dialog: a grid, because there are seven and counting. */
fieldset.field { border: 0; padding: 0; min-width: 0; }
.type-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr)); gap: .1rem .8rem; }
.type-grid .check { margin-bottom: .3rem; }

/* ---- the product page ---- */
/* What a card holds, read as label and value — not a form: every change is a dialog. */
.facts { display: grid; grid-template-columns: max-content 1fr; gap: .3rem 1.2rem; margin: .8rem 0 0; font-size: .92rem; }
.facts dt { color: var(--ink-3); }
.facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.photo-row { display: flex; gap: 1.2rem; align-items: flex-start; flex-wrap: wrap; margin-top: .8rem; }
.photo {
    width: 160px;
    height: 160px;
    object-fit: contain;
    background: #fff;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
}
.photo-none {
    width: 160px;
    height: 160px;
    display: grid;
    place-items: center;
    align-content: center;
    gap: .3rem;
    border: 1px dashed var(--rule-2);
    border-radius: var(--radius);
    color: var(--ink-3);
    font-size: .85rem;
}
.axis-slot { border: 1px solid var(--rule); border-radius: var(--radius); padding: .7rem .9rem .4rem; margin-bottom: .7rem; }
.chip-row { display: flex; flex-wrap: wrap; gap: .35rem; margin: 0 0 .5rem; }
.entry .row-list { border-radius: var(--radius); margin-top: .6rem; }

/* The content column is a flex item, and a flex item will not shrink below its widest content by
   default — so one wide table widened the whole column past the sidebar and the page scrolled
   sideways, instead of the table scrolling inside its own .table-scroll box as it is meant to. */
.shell > .content { min-width: 0; }

/* What a confirmation will do, one consequence to a line. */
.consequences { margin: 0 0 1rem; padding-inline-start: 1.2rem; font-size: .9rem; color: var(--ink-2); }
.consequences li { margin-bottom: .25rem; }

.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;
}

@media (max-width: 560px) {
    .field-row { flex-wrap: wrap; }
    .field-row > .field.narrow { flex: 1 1 100%; }
}
