/* ============================================================
   Doceye — Portal & Dashboard
   ============================================================
   Flat, minimal, sharp. Following the Eyeston CMR house rules:
     · border-radius: 0 everywhere (the spinner is the sole exception)
     · no drop shadows, no gradients, no backdrop blur
     · a 1px --line border does the separating work shadows used to
     · semantic tokens (--ink / --muted / --line / --panel), not literals
     · uppercase micro-labels with 0.08em tracking
   Brand ramp sampled from assets/logos/whitetheme.png.
   ============================================================ */

/* NO @import here, deliberately. A CSS @import is render-blocking and
   serialised: the browser will not paint until it resolves. On a phone whose
   Wi-Fi has no internet route, that meant a blank page until the request to
   Google timed out. Inter is now loaded from a non-blocking <link> in each
   view instead, and the system stack below renders instantly meanwhile. */

:root {
    /* Inter, not the Eyeston CMR Futura stack. Futura is a geometric face
       with a low x-height — its lowercase measures 42px where Inter's is
       55px at the same size, a 31% difference. Gorgeous in a logo, but it
       made body copy, prices and payment references hard to read on a
       phone, which is where nearly all of this traffic lands. The brand
       still speaks through the logo artwork and the orange ramp.
       Inter leads; the system faces are only a fallback while it loads
       (the import uses display=swap, so text is never invisible). */
    --font-brand: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

    /* ── Brand ramp — the four blades of the logo mark ───────── */
    --brand-amber:  #FE9506;
    --brand-orange: #F96D26;
    --brand-ember:  #DF4329;
    --brand-brick:  #C0392B;

    --radius: 0;
    --shadow: none;

    /* ── The brand split ─────────────────────────────────────────
       Adapted from Eyeston CMR's --lp-split. There it is two colours
       meeting at ONE shared offset, so the result is a hard diagonal
       cut rather than a blend — which is exactly why a "gradient" is
       permitted inside a flat system: it reads as identity, not as
       decoration or depth.

       Doceye's mark is four blades, not two, so its split carries four
       bands. Every stop pair shares its offset, so there are three hard
       cuts and no soft transition anywhere. Use it sparingly. */
    --split: linear-gradient(115deg,
        var(--brand-amber)  0 25%,
        var(--brand-orange) 25% 50%,
        var(--brand-ember)  50% 75%,
        var(--brand-brick)  75% 100%);
    --split-v: linear-gradient(180deg,
        var(--brand-amber)  0 25%,
        var(--brand-orange) 25% 50%,
        var(--brand-ember)  50% 75%,
        var(--brand-brick)  75% 100%);
}

/* Nothing renders these. They stay defined because they encode the mark's
   real construction, and the logo artwork is now the only place the orange
   appears at all. The interface itself is monochrome. */

/* ── Dark (default — "the brand colour is black") ────────────
   Applies when no theme is set, and when dark is chosen explicitly. */
:root,
:root[data-theme="dark"] {
    color-scheme: dark;

    --bg: #0A0A0A;
    --bg-deep: #000000;
    --panel: #131313;
    --panel-raised: #1B1B1B;

    --ink: #F7F7F6;
    --muted: #9A9A96;
    --line: #262626;
    --line-strong: #3A3A3A;

    /* The interface is monochrome. Large saturated fills read as shouting
       on a phone, where the screen is small and mostly one surface, so the
       orange lives in the logo and nowhere else. --accent is the neutral
       that paints fills and borders; --accent-ink is its text counterpart. */
    --accent: #F0F0EE;
    --accent-ink: #F0F0EE;
    --accent-2: #C9C9C4;
    --on-accent: #0A0A0A;                /* sits on the light fill */

    /* A warm sage rather than a neon green — sits in the same warm family
       as the orange ramp instead of fighting it. Still used for outcome
       states (fulfilled, sent, paid) in the admin. */
    /* Status, not brand. Kept visible because a warning that looks like
       everything else is not a warning, but desaturated so they read as
       state rather than decoration. */
    --success: #7FA55A;
    --warning: #C08A3E;
    --danger: #C4685C;
}

/* ── Light ───────────────────────────────────────────────────
   The ramp inverts its roles: amber and orange are too light to
   carry text on white, so brick — "depth only" in dark mode —
   becomes the text accent at 5.3:1. Fills stay vivid orange. */
:root[data-theme="light"] {
    color-scheme: light;

    --bg: #F4F4F2;
    --bg-deep: #FFFFFF;
    --panel: #FFFFFF;
    --panel-raised: #F0EFEC;

    --ink: #141413;
    --muted: #66665F;
    --line: #E3E2DE;
    --line-strong: #C7C6C1;

    --accent: #1F1F1E;
    --accent-ink: #1F1F1E;
    --accent-2: #4A4A46;
    --on-accent: #FFFFFF;                /* sits on the dark fill */

    --success: #4F6E33;
    --warning: #8A5A17;
    --danger: #9B3B30;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    font-family: var(--font-brand);
    background-color: var(--bg);
    color: var(--ink);
    overflow-x: hidden;
    -webkit-font-smoothing: antialiased;
    position: relative;
}

/* ── Wordmark watermark ──────────────────────────────────────
   "Doceye" set huge in the brand face and bled off the bottom-right
   corner. Fixed, so it holds still while the page scrolls, and
   pointer-events:none so it never intercepts a click. It sits at
   z-index 0 — above the body fill but beneath every direct child,
   which is raised to 1. Light mode needs slightly more opacity:
   dark ink on a near-white ground carries less than light ink on
   black at the same value. */
body::before {
    content: "doceye";   /* lowercase, matching the wordmark */
    position: fixed;
    right: -0.04em;
    bottom: -0.42em;
    font-family: var(--font-brand);
    font-size: 21vw;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--ink);
    opacity: 0.028;
    pointer-events: none;
    user-select: none;
    white-space: nowrap;
    z-index: 0;
}
:root[data-theme="light"] body::before { opacity: 0.038; }
body > * { position: relative; z-index: 1; }

h1, h2, h3, h4 { font-weight: 600; letter-spacing: 0; }

/* ── Icon system ──────────────────────────────────────────────
   Symbols live in views/partials/icons.php; colour and weight
   come from here so every icon inherits currentColor. */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.ico {
    width: 1em;
    height: 1em;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.75;
    stroke-linecap: square;
    stroke-linejoin: miter;
    flex-shrink: 0;
    display: inline-block;
    vertical-align: -0.14em;
}
.ico--sm { width: 0.85em; height: 0.85em; }
.ico--lg { width: 1.4em; height: 1.4em; }
/* Third-party logos are drawn as solid shapes, not stroked outlines. */
.ico--solid { fill: currentColor; stroke: none; }

/* Round by request — a deliberate exception to the radius:0 rule, the
   same way Eyeston CMR keeps its notification bell and theme toggle
   round while squaring everything else. Used for categorical legends;
   the live-presence variant was removed with the fake doctor statuses. */
.status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--muted);
    display: inline-block;
    vertical-align: 0.02em;
    margin-right: 7px;
}
/* Legend markers. Separated by lightness rather than hue, so a chart key
   still reads without introducing colour. */
.status-dot--ramp-1 { background: var(--ink); }
.status-dot--ramp-2 { background: var(--muted); }
.status-dot--ramp-3 { background: var(--line-strong); }
.status-dot--ramp-4 { background: var(--line); }

/* ── Brand lockup ─────────────────────────────────────────────
   Wordmark, hairline rule, then the descriptor in tracked caps.
   The negative right margin cancels the trailing letter-space so
   the tag optically centres against the rule. */
.brand { display: flex; align-items: center; gap: 13px; text-decoration: none; }
.brand__mark { display: flex; align-items: center; }
.brand__rule {
    width: 1px;
    height: 22px;
    background: var(--line-strong);
    flex-shrink: 0;
}
.brand__tag {
    font-size: 0.74rem;
    font-weight: 500;
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: 0.24em;
    margin-right: -0.24em;
    color: var(--muted);
    white-space: nowrap;
    padding-top: 1px;
}

/* ── Theme swaps ──────────────────────────────────────────────
   The logo ships in two cuts: white wordmark for dark, black for
   light. The toggle shows the theme you'd switch *to*. */
/* Specificity has to clear `.portal-nav .logo img { display: block }`,
   hence the :root guard rather than a bare `.logo .logo-light`. */
:root:not([data-theme="light"]) .logo img.logo-light { display: none; }
:root[data-theme="light"] .logo img.logo-dark { display: none; }
:root[data-theme="light"] .logo img.logo-light { display: block; }

.theme-toggle .ico-moon { display: none; }
:root[data-theme="light"] .theme-toggle .ico-sun { display: none; }
:root[data-theme="light"] .theme-toggle .ico-moon { display: inline-block; }

/* Uppercase micro-label, the house kicker treatment. Was 0.68rem, which
   rendered at 10.9px: too small to read comfortably on a phone, and these
   labels carry real information like "next available today". */
.kicker {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
}

/* ── Buttons ──────────────────────────────────────────────── */
.btn-primary,
.btn-gold,
.btn-outline {
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    padding: 11px 20px;
    border-radius: 0;
    cursor: pointer;
    text-align: center;
    letter-spacing: 0.01em;
    transition: background-color 0.15s, color 0.15s, border-color 0.15s;
}
.btn-primary {
    background: var(--accent);
    color: var(--on-accent);
    border: 1px solid var(--accent);
}
.btn-primary:hover { background: var(--accent-2); border-color: var(--accent-2); }

.btn-gold {
    background: var(--accent-2);
    color: var(--on-accent);
    border: 1px solid var(--accent-2);
}
.btn-gold:hover { background: var(--accent); border-color: var(--accent); }

/* The one coloured element in the interface. Everything else is monochrome,
   so the brand orange lands entirely on the single action that matters, and
   nothing on the page competes with it. Sampled from the logo mark, where
   it is the dominant blade. Near-black label rather than white: 7.2:1
   against this orange versus 2.9:1 for white, and it holds in both themes
   because the fill does not change with the theme. */
.btn-split {
    /* Arced, not slanted, and a true circle so the curve is never squashed.
       An ellipse stretched to bend the edges across something this wide
       turns the bands into pointed lens shapes, which reads as distortion.
       Instead the centre sits well below the button: the arcs crossing it
       are then a genuine circular sweep, curved but undistorted, like the
       blades of the mark.

       Colour order follows the mark: ember innermost, orange, amber
       outside. Each stop pair shares one offset, so these are knife cuts
       with no intermediate colour. Near-black label clears AA on all three:
       ember 5.0, orange 7.2, amber 9.5. */
    background: radial-gradient(circle at -10% 210%,
        var(--brand-ember)  0 55%,
        var(--brand-orange) 55% 76%,
        var(--brand-amber)  76% 100%);
    border-color: transparent;
    color: #0A0A0A;
}
/* Hover melts the cuts: same three colours on the same arc, but the stops
   pull apart so the bands blend into each other. Only the edges change, so
   the button never appears to move or flash. */
.btn-split:hover {
    background: radial-gradient(circle at -10% 210%,
        var(--brand-ember)  0%,
        var(--brand-orange) 66%,
        var(--brand-amber)  100%);
    border-color: transparent;
    filter: none;
}

.btn-outline {
    background: transparent;
    border: 1px solid var(--line-strong);
    color: var(--ink);
}
.btn-outline:hover { border-color: var(--accent); color: var(--accent-ink); }

button[disabled] { opacity: 0.45; cursor: not-allowed; }

/* ── Card ─────────────────────────────────────────────────── */
.card {
    background-color: var(--panel);
    border: 1px solid var(--line);
    border-radius: 0;
    padding: 20px;
}

/* ── Portal nav ───────────────────────────────────────────── */
.portal-nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 40px;
    border-bottom: 1px solid var(--line);
    background: var(--bg-deep);
}
.portal-nav .logo { display: flex; align-items: center; text-decoration: none; }
/* The Doceye wordmark stacks "doc" over "eye", so it is roughly half the
   width of a single-line lockup at the same height and needs a little more
   of it to hold its own beside the nav. */
.portal-nav .logo img { height: 40px; width: auto; display: block; }
.portal-nav .links { display: flex; gap: 28px; }
.portal-nav .links a {
    color: var(--muted);
    text-decoration: none;
    font-weight: 500;
    font-size: 0.9rem;
    padding-bottom: 2px;
    border-bottom: 1px solid transparent;
}
.portal-nav .links a.active,
.portal-nav .links a:hover { color: var(--ink); border-bottom-color: var(--accent); }
.portal-nav .actions { display: flex; align-items: center; gap: 18px; }
.portal-nav .actions .icon {
    color: var(--muted);
    font-size: 1.15rem;
    cursor: pointer;
    display: flex;
    background: none;
    border: none;
    padding: 0;
}
.portal-nav .actions .icon:hover { color: var(--accent-ink); }
.portal-nav .actions .avatar {
    width: 34px; height: 34px;
    border-radius: 0;
    overflow: hidden;
    border: 1px solid var(--line-strong);
}
.portal-nav .actions .avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

.portal-container { max-width: 1400px; margin: 32px auto; padding: 0 20px; }

/* ── Content pages (how-it-works, doctors) ────────────────── */
.page-head { max-width: 720px; margin: 8px 0 32px; }
.page-head h1 { font-size: clamp(1.5rem, 4vw, 2.1rem); margin: 10px 0 14px; letter-spacing: -0.01em; }
.page-head p { color: var(--muted); font-size: 0.95rem; line-height: 1.65; }

.steps-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 20px;
}
.step-card h4 { font-size: 1rem; margin: 14px 0 8px; }
.step-card p { color: var(--muted); font-size: 0.87rem; line-height: 1.65; }

.plain-list { list-style: none; display: flex; flex-direction: column; }
.plain-list li {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    padding: 11px 0;
    border-bottom: 1px solid var(--line);
    font-size: 0.87rem;
    color: var(--muted);
    line-height: 1.6;
}
.plain-list li:last-child { border-bottom: none; }
.plain-list .ico { color: var(--muted); margin-top: 3px; }

.price-figure { font-size: 2.1rem; font-weight: 600; margin: 4px 0 10px; letter-spacing: -0.01em; }

/* Says plainly what the service cannot do. Set apart so it reads as candour
   rather than small print. */
.honest-note { margin-top: 40px; border-left: 2px solid var(--line-strong); }
.honest-note p { color: var(--muted); font-size: 0.89rem; line-height: 1.7; }

.doctors-page-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 20px;
}
.doctor-profile { display: flex; flex-direction: column; }
/* Square, matching the square the photo was cropped to at upload
   (public/js/crop.js) and the 96px card on the homepage. It used to be a
   220px landscape band, which quietly re-cropped every portrait a second
   time and took the top off people's heads. One shape, chosen once by
   whoever framed the photo, is the whole point of the cropper. */
.doctor-profile img {
    width: 100%;
    aspect-ratio: 1 / 1;
    height: auto;
    object-fit: cover;
    object-position: center;
    border: 1px solid var(--line);
    margin-bottom: 16px;
}
.doctor-profile__body h4 { font-size: 1.05rem; margin: 6px 0 10px; }
.doctor-profile__body p { color: var(--muted); font-size: 0.87rem; line-height: 1.65; }

.portal-top-grid {
    display: grid;
    grid-template-columns: 1.5fr 1fr;
    gap: 20px;
    margin-bottom: 40px;
}

/* ── Consultation panel ───────────────────────────────────── */
.consultation-card {
    background: var(--panel);
    display: flex;
    gap: 22px;
    position: relative;
}
/* Fills the panel's full height as a column. align-self:stretch plus
   object-fit:cover crops rather than squashes, and height:auto stops the
   HTML height attribute (there to reserve space and avoid layout shift)
   from forcing the box to the photo's own 408px. */
.consultation-card .doc-img {
    width: 150px;
    height: auto;
    align-self: stretch;
    object-fit: cover;
    /* This was a hand-measured 20%, picked for one specific photo and wrong
       for every other. The image is now cropped to 3:2 with the subject
       centred before it is ever uploaded (public/js/crop.js), so the middle
       is the right place to take from, whatever shape this box becomes. */
    object-position: center;
    border-radius: 0;
    border: 1px solid var(--line);
}
.consultation-card .info h2 { font-size: 1.25rem; margin-bottom: 8px; }
.consultation-card .info p { font-size: 0.86rem; color: var(--muted); margin-bottom: 12px; }
.consultation-card .meta-line { display: flex; align-items: center; gap: 7px; color: var(--muted); font-size: 0.82rem; }
.consultation-card .times { display: flex; gap: 8px; margin-bottom: 18px; }
.consultation-card .time-pill {
    background: var(--panel-raised);
    border: 1px solid var(--line);
    padding: 5px 11px;
    border-radius: 0;
    font-size: 0.78rem;
    color: var(--ink);
}

/* ── Journey ──────────────────────────────────────────────── */
.journey-card h3 { font-size: 1rem; margin-bottom: 15px; }
.journey-timeline { display: flex; flex-direction: column; gap: 18px; }
.journey-step { display: flex; gap: 14px; font-size: 0.85rem; align-items: flex-start; }
.journey-num {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 0;
    background: transparent;
    border: 1px solid var(--line-strong);
    color: var(--muted);
    font-size: 0.9rem;
    font-weight: 600;
}
/* Previously the three steps walked the orange ramp. Numbered outlines
   carry the sequence on their own without three colours doing it. */

/* ── Shop ─────────────────────────────────────────────────── */
/* Section heading. .shop-header is the legacy alias, kept so the shop
   markup drops straight back in if commerce returns to the homepage. */
.section-head,
.shop-header { margin-bottom: 18px; font-size: 1.15rem; font-weight: 600; }
.shop-layout { display: grid; grid-template-columns: 1fr 300px; gap: 20px; align-items: start; }
.shop-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px; }
.shop-empty {
    grid-column: 1 / -1;
    text-align: center;
    color: var(--muted);
    padding: 40px 0;
    font-size: 0.9rem;
}

.locations { list-style: none; display: flex; flex-direction: column; }
.locations li {
    display: flex;
    gap: 11px;
    align-items: flex-start;
    padding: 11px 0;
    border-bottom: 1px solid var(--line);
    font-size: 0.82rem;
    color: var(--muted);
    line-height: 1.5;
}
.locations li:last-child { border-bottom: none; }
.locations li strong { color: var(--ink); font-weight: 600; }
.locations .ico { color: var(--accent-ink); margin-top: 2px; }

.product-card {
    display: flex;
    flex-direction: column;
    position: relative;
    transition: border-color 0.15s;
}
.product-card:hover { border-color: var(--line-strong); }
.product-card .img-wrapper {
    background: var(--bg-deep);
    border: 1px solid var(--line);
    border-radius: 0;
    text-align: center;
    margin-bottom: 16px;
    height: 132px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--accent-ink);
}
.product-card .img-wrapper img { max-height: 100%; max-width: 100%; object-fit: contain; }
.product-card .img-wrapper .ico { width: 40px; height: 40px; stroke-width: 1.5; }
.product-card h4 { font-size: 1rem; margin-bottom: 6px; }
.product-card p { font-size: 0.8rem; color: var(--muted); margin-bottom: 16px; flex: 1; line-height: 1.5; }
.product-card .price { font-weight: 600; margin-bottom: 14px; font-size: 1.05rem; }
.product-card .price-sub {
    display: block;
    font-size: 0.72rem;
    font-weight: 400;
    color: var(--muted);
    margin-top: 3px;
    letter-spacing: 0.02em;
}
.product-card .product-tryon {
    margin-bottom: 8px;
    font-size: 0.76rem;
    padding: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
}

.product-badge {
    position: absolute;
    top: 21px;
    right: 21px;
    font-size: 0.6rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 4px 8px;
    border-radius: 0;
    background: var(--bg-deep);
    border: 1px solid var(--line-strong);
    color: var(--muted);
    z-index: 1;
}
/* Product types used to take a blade of the orange ramp each. The type is
   already spelled out in the badge, so the colour was decoration; icons
   and badges are now monochrome. */
.product-card .img-wrapper { color: var(--muted); }
.product-badge { color: var(--muted); border-color: var(--line-strong); }

/* ── Doctor cards ─────────────────────────────────────────── */
/* ── Doctor roster ───────────────────────────────────────────
   A row, not a centred stack: the card is ~440px wide, so a 72px
   avatar floating in the middle wasted most of it. Portrait left,
   specialty as a kicker above the name. Presence statuses used to sit
   in a right-hand column here; they were removed because nothing in
   the system could ever set them — see views/home.php. */
.doctors-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 20px;
    margin-bottom: 40px;
}
.doctor-card {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 0;
    padding: 20px;
    display: flex;
    align-items: flex-start;
    gap: 18px;
    transition: border-color 0.15s;
}
.doctor-card { text-decoration: none; color: inherit; }
.doctor-card:hover { border-color: var(--line-strong); }
.doctor-card img {
    width: 96px;
    height: 96px;
    border-radius: 0;
    object-fit: cover;
    border: 1px solid var(--line-strong);
    flex-shrink: 0;
    display: block;
}
/* Name block centres against the portrait; the status stays top-aligned
   so it keeps its scan column. */
.doctor-card__body { flex: 1; min-width: 0; align-self: center; }
.doctor-card__body .kicker { display: block; margin-bottom: 7px; }
.doctor-card h4 { font-size: 1.05rem; margin: 0; }

/* ── Admin ────────────────────────────────────────────────── */
.admin-layout { display: flex; min-height: 100vh; }
.admin-sidebar {
    width: 240px;
    background-color: var(--bg-deep);
    border-right: 1px solid var(--line);
    display: flex;
    flex-direction: column;
}
.admin-sidebar .logo {
    padding: 22px 18px;
    border-bottom: 1px solid var(--line);
}
/* The rail is narrow, so the lockup runs a size down from the portal's. */
.admin-sidebar .logo img { height: 32px; width: auto; display: block; }
.admin-sidebar .brand { gap: 11px; }
.admin-sidebar .brand__rule { height: 19px; }
.admin-sidebar .brand__tag { font-size: 0.72rem; letter-spacing: 0.1em; margin-right: -0.1em; }
.admin-sidebar .nav { padding: 16px 0; display: flex; flex-direction: column; }
.admin-sidebar .nav a {
    padding: 13px 20px;   /* clears a 44px tap target */
    color: var(--muted);
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 0.88rem;
    border-left: 2px solid transparent;
}
.admin-sidebar .nav a .ico { width: 17px; height: 17px; }
.admin-sidebar .nav a:hover { color: var(--ink); }
.admin-sidebar .nav a.active {
    background: var(--panel);
    color: var(--accent-ink);
    border-left-color: var(--accent);
}

.admin-main { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
.admin-header {
    height: 66px;
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 30px;
}
.admin-header h1 { font-size: 1.2rem; font-weight: 600; }
.admin-header .actions { display: flex; align-items: center; gap: 18px; }
.admin-header .actions .icon-btn {
    background: none;
    border: none;
    color: var(--muted);
    cursor: pointer;
    font-size: 1.1rem;
    display: flex;
    padding: 0;
}
.admin-header .actions .icon-btn:hover { color: var(--accent-ink); }
.admin-header .actions img { width: 34px; height: 34px; border-radius: 0; border: 1px solid var(--line-strong); object-fit: cover; }

.admin-content { padding: 24px 30px; }
.admin-grid-top {
    display: grid;
    grid-template-columns: 1.2fr 1fr 1fr;
    gap: 20px;
    margin-bottom: 20px;
}
.admin-grid-bottom { display: grid; grid-template-columns: 1.5fr 1fr; gap: 20px; }

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}
.card-head h3 { font-size: 0.95rem; font-weight: 600; }
.card-head .ico { color: var(--muted); }

.revenue-card .amount { font-size: 1.9rem; font-weight: 600; margin: 8px 0 4px; letter-spacing: -0.01em; }
.revenue-card .delta { display: flex; align-items: center; gap: 6px; font-size: 0.82rem; color: var(--success); }
.revenue-card .chart-placeholder {
    height: 90px;
    background: repeating-linear-gradient(90deg, var(--panel-raised) 0 3px, transparent 3px 8px);
    border-bottom: 1px solid var(--accent);
    margin-top: 16px;
    border-radius: 0;
}
.revenue-card .breakdown { display: flex; gap: 16px; font-size: 0.76rem; margin-top: 12px; color: var(--muted); }

.triage-card .feed-item {
    background: var(--panel-raised);
    padding: 10px 13px;
    border-radius: 0;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 0.83rem;
    border-left: 2px solid var(--line-strong);
}
.triage-card .feed-item .count {
    margin-left: auto;
    background: var(--bg-deep);
    border: 1px solid var(--line);
    padding: 1px 7px;
    font-size: 0.75rem;
}
.triage-card .feed-item.active  { border-left-color: var(--success); }
.triage-card .feed-item.warning { border-left-color: var(--warning); }
.triage-card .feed-item.danger  { border-left-color: var(--danger); }
.triage-card .feed-item.warning .ico { color: var(--warning); }
.triage-card .feed-item.danger .ico  { color: var(--danger); }

.calls-card table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.calls-card th, .calls-card td { padding: 9px 0; border-bottom: 1px solid var(--line); text-align: left; }
.calls-card th {
    color: var(--muted);
    font-weight: 600;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.calls-card .total-row {
    display: flex;
    justify-content: space-between;
    margin-top: 14px;
    font-size: 0.85rem;
}

.ecommerce-card .list { flex: 1; }
.fulfillment-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 11px 0;
    border-bottom: 1px solid var(--line);
    font-size: 0.85rem;
}
.fulfillment-item:last-child { border: none; }
.fulfillment-item .thumb {
    width: 36px; height: 36px;
    background: var(--bg-deep);
    border: 1px solid var(--line);
    display: flex; align-items: center; justify-content: center;
    color: var(--accent-ink);
}
.fulfillment-item .thumb .ico { width: 18px; height: 18px; }

/* Awaiting-payment queue — one row per unconfirmed bank transfer. */
.pending-card { border-left: 2px solid var(--warning); }
.pending-row {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 0;
    border-bottom: 1px solid var(--line);
}
.pending-row:last-of-type { border-bottom: none; }
.pending-row__who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; font-size: 0.78rem; color: var(--muted); }
.pending-row__who strong { font-size: 0.92rem; color: var(--ink); font-weight: 600; }
.pending-row__amount { font-size: 1rem; font-weight: 600; white-space: nowrap; }

@media (max-width: 700px) {
    .pending-row { flex-wrap: wrap; }
    .pending-row form { width: 100%; }
    .pending-row form button { width: 100%; }
}

.supplier-card .order-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    padding: 10px 13px;
    background: var(--panel-raised);
    border-radius: 0;
    margin-bottom: 8px;
    font-size: 0.82rem;
}
.supplier-card .order-item .label { display: flex; align-items: center; gap: 9px; }
.empty-note { color: var(--muted); font-size: 0.83rem; }

/* ── Utils ────────────────────────────────────────────────── */
.hidden { display: none !important; }
.text-success { color: var(--success); }
.text-warning { color: var(--warning); }
.text-danger  { color: var(--danger); }

/* ── Chat widget ──────────────────────────────────────────── */
.chat-widget-btn {
    position: fixed;
    bottom: 24px;
    right: 24px;
    height: 48px;
    /* Was a panel-coloured square with a hairline border, which disappeared
       against the page. Now a solid high-contrast slab carrying a label, so
       it reads as an action rather than an icon. Stays monochrome: the
       orange belongs to the booking button, and two competing colours would
       leave neither one primary. */
    background: var(--ink);
    border: 1px solid var(--ink);
    border-radius: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    padding: 0 18px;
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--bg);
    cursor: pointer;
    z-index: 1000;
    transition: opacity 0.15s;
}
.chat-widget-btn .ico { width: 17px; height: 17px; stroke-width: 2; }
.chat-widget-btn:hover { opacity: 0.86; }
/* Scrim behind the chat. Without it the panel floats over live content and
   the page keeps competing for attention, which is worst on a phone where
   the panel covers most of the screen anyway. Tapping it closes the chat. */
.chat-scrim {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: 999;
    opacity: 0;
    transition: opacity 0.18s ease;
}
.chat-scrim.open { opacity: 1; }
:root[data-theme="light"] .chat-scrim { background: rgba(20, 20, 19, 0.4); }

/* Stops the page scrolling behind the open panel. */
body.chat-open { overflow: hidden; }

.chat-widget-window {
    position: fixed;
    bottom: 92px;
    right: 28px;
    width: 330px;
    background: var(--panel);
    border: 1px solid var(--line-strong);
    border-radius: 0;
    display: none;
    flex-direction: column;
    z-index: 1000;
    overflow: hidden;
}
.chat-widget-window.open { display: flex; }
.chat-widget-header {
    background: var(--panel-raised);
    border-bottom: 1px solid var(--line);
    padding: 13px 15px;
    color: var(--ink);
    font-weight: 600;
    font-size: 0.88rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.chat-widget-header button {
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    display: flex;
    padding: 0;
    font-size: 1rem;
}
.chat-widget-body {
    padding: 15px;
    height: 260px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 9px;
}
.chat-widget-msg {
    padding: 9px 11px;
    border-radius: 0;
    font-size: 0.82rem;
    max-width: 88%;
    line-height: 1.5;
}
.chat-widget-msg.bot {
    background: var(--panel-raised);
    border-left: 2px solid var(--line-strong);
    align-self: flex-start;
}
.chat-widget-msg.user {
    background: transparent;
    border: 1px solid var(--line-strong);
    color: var(--ink);
    align-self: flex-end;
}
.chat-action {
    align-self: flex-start;
    font-size: 0.78rem;
    padding: 8px 13px;
}
.chat-widget-footer {
    padding: 12px 15px;
    border-top: 1px solid var(--line);
    display: flex;
    gap: 9px;
}
.chat-widget-footer input {
    flex: 1;
    padding: 9px 11px;
    border-radius: 0;
    border: 1px solid var(--line);
    background: var(--bg);
    color: var(--ink);
    font-family: inherit;
    font-size: 0.82rem;
    outline: none;
}
.chat-widget-footer input:focus { border-color: var(--accent); }
.chat-widget-footer button {
    background: transparent;
    color: var(--ink);
    border: 1px solid var(--line-strong);
    border-radius: 0;
    width: 34px;
    height: 34px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: border-color 0.15s;
}
.chat-widget-footer button:hover { border-color: var(--ink); }

/* ── Modals ───────────────────────────────────────────────── */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.82);
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
    z-index: 2000;
}
.modal-overlay--active { display: flex; }
.modal {
    background: var(--panel);
    border: 1px solid var(--line-strong);
    border-radius: 0;
    box-shadow: none;
    width: 100%;
    max-width: 440px;
    max-height: 90vh;
    overflow-y: auto;
}
.modal--wide { max-width: 860px; }
.modal__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 15px;
    padding: 20px 24px 0;
}
.modal__header h3 { font-size: 1.1rem; }
.modal__info {
    font-size: 0.78rem;
    color: var(--accent-ink);
    margin-top: 5px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.modal__close {
    background: none;
    border: none;
    color: var(--muted);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    padding: 0;
    display: flex;
}
.modal__close:hover { color: var(--ink); }
.modal__body { padding: 20px 24px 24px; }

.field { margin-bottom: 14px; }
.field label {
    display: block;
    font-size: 0.78rem;   /* 0.68rem rendered at 10.9px, too small for a form */
    color: var(--muted);
    margin-bottom: 7px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
}
.field input,
.field textarea {
    width: 100%;
    padding: 10px 12px;
    border-radius: 0;
    border: 1px solid var(--line);
    background: var(--bg);
    color: var(--ink);
    font-family: inherit;
    font-size: 0.9rem;
    outline: none;
    transition: border-color 0.15s;
}
.field input:focus,
.field textarea:focus { border-color: var(--accent); }
.field textarea { resize: vertical; min-height: 70px; }
.modal__note { font-size: 0.74rem; color: var(--muted); margin-top: 12px; text-align: center; }

#tryon-container {
    height: 60vh;
    min-height: 320px;
    background: var(--bg-deep);
    border: 1px solid var(--line);
    border-radius: 0;
    overflow: hidden;
}
#tryon-container iframe { width: 100%; height: 100%; border: none; }
.tryon-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    gap: 14px;
    color: var(--muted);
    text-align: center;
    padding: 20px;
}
.tryon-placeholder .ico { width: 46px; height: 46px; color: var(--accent-ink); stroke-width: 1.5; }
.tryon-placeholder__hint { font-size: 0.78rem; opacity: 0.75; }

/* ── Spinner — the one intentional curve ──────────────────── */
.spinner {
    display: inline-block;
    width: 12px;
    height: 12px;
    border: 2px solid rgba(0, 0, 0, 0.3);
    border-top-color: var(--on-accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
    vertical-align: -2px;
    margin-right: 7px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Toasts ───────────────────────────────────────────────── */
#toast-container {
    position: fixed;
    top: 20px;
    right: 20px;
    display: flex;
    flex-direction: column;
    gap: 9px;
    z-index: 3000;
}
.toast {
    padding: 12px 16px;
    border-radius: 0;
    font-size: 0.85rem;
    color: var(--ink);
    border: 1px solid var(--line-strong);
    border-left-width: 2px;
    background: var(--panel);
    max-width: 340px;
    transition: opacity 0.25s;
}
.toast--success { border-left-color: var(--success); }
.toast--error   { border-left-color: var(--danger); }

/* ── Footer ───────────────────────────────────────────────── */
.portal-footer {
    padding: 28px 40px;
    color: var(--muted);
    font-size: 0.82rem;
    border-top: 1px solid var(--line);
    display: flex;
    justify-content: space-between;
    max-width: 1400px;
    margin: 0 auto;
}
.portal-footer a { color: inherit; margin-right: 18px; text-decoration: none; }
.portal-footer a:hover { color: var(--accent-ink); }

/* ── WhatsApp handoff ─────────────────────────────────────── */
/* Sends the patient into the real WhatsApp thread carrying what they just
   typed. That inbound message opens Meta's 24-hour window, which is what
   makes every later confirmation deliverable as free-form text. */
/* Outlined rather than WhatsApp green. The glyph already says which app
   this opens, so the colour was only adding noise. */
.wa-handoff {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    width: 100%;
    margin-top: 4px;
    background: transparent;
    color: var(--ink);
    border: 1px solid var(--line-strong);
    font-size: 0.82rem;
    font-weight: 600;
    padding: 11px 16px;
    text-decoration: none;
    cursor: pointer;
    transition: border-color 0.15s;
}
.wa-handoff:hover { border-color: var(--ink); }
.wa-handoff .ico { width: 15px; height: 15px; color: var(--muted); }

/* ── Responsive ───────────────────────────────────────────── */

/* Nearly all traffic arrives from Facebook, Instagram and WhatsApp, so the
   phone is the primary target: every control gets a 44px tap area, and
   inputs sit at 16px so iOS does not zoom the page on focus. */
@media (max-width: 900px) {
    .btn-primary,
    .btn-gold,
    .btn-outline,
    .wa-handoff,
    .chat-widget-footer button,
    .portal-nav .actions .icon,
    .admin-header .actions .icon-btn { min-height: 44px; }

    .portal-nav .actions .icon,
    .admin-header .actions .icon-btn { min-width: 44px; align-items: center; justify-content: center; }

    .field input, .field textarea, .chat-widget-footer input { font-size: 16px; }
}

@media (max-width: 900px) {
    .portal-nav { flex-wrap: wrap; gap: 12px; padding: 14px 20px; }
    .portal-nav .brand__rule, .portal-nav .brand__tag { display: none; }
    /* Inter is wider than the old face, so each link needs nowrap or the
       labels break mid-phrase; the row scrolls sideways instead. Padding
       gives each one a 44px tap target: they were 20px tall, which is a
       coin-flip to hit with a thumb. */
    .portal-nav .links { gap: 4px; order: 3; width: 100%; overflow-x: auto; scrollbar-width: none; margin: 0 -4px; }
    .portal-nav .links::-webkit-scrollbar { display: none; }
    .portal-nav .links a {
        white-space: nowrap;
        flex-shrink: 0;
        padding: 12px 10px;
        display: flex;
        align-items: center;
        min-height: 44px;
    }
    .portal-nav .logo { min-height: 44px; align-items: center; }
    .portal-nav .actions .avatar { width: 40px; height: 40px; }

    /* Admin header controls were spilling past the viewport at 320px. */
    .admin-header { padding: 0 16px; gap: 10px; }
    .admin-header h1 { font-size: 1.05rem; }
    .admin-header .actions { gap: 8px; flex-shrink: 0; }
    .admin-header .actions img { width: 32px; height: 32px; }

    /* Footer links were 16px tall, and the table's Join Call buttons 25px.
       Both are real actions and need a thumb-sized target. */
    .portal-footer a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        margin-right: 14px;
    }
    .calls-card .btn-outline,
    .pending-row .btn-primary { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
    .calls-card td { padding: 12px 0; }
    .portal-top-grid { grid-template-columns: 1fr; }
    .shop-layout { grid-template-columns: 1fr; }
    .consultation-card { flex-direction: column; }
    /* Stacked on a phone: full width, cropped to a banner rather than a
       tall column. Still centred, for the same reason as the desktop rule. */
    .consultation-card .doc-img {
        width: 100%;
        height: 190px;
        align-self: auto;
        object-position: center;
    }
    .admin-layout { flex-direction: column; }
    .admin-sidebar { width: 100%; }
    .admin-grid-top, .admin-grid-bottom { grid-template-columns: 1fr; }
    .ecommerce-card { flex-direction: column; }
    .portal-footer { flex-direction: column; gap: 12px; padding: 24px 20px; }
    #toast-container { left: 16px; right: 16px; }
    .toast { max-width: none; }
}

/* On a phone the chat is the whole task, so it becomes a sheet rather than a
   small floating card, and the launcher gets out of its way. */
@media (max-width: 560px) {
    .chat-widget-window {
        left: 10px;
        right: 10px;
        bottom: 10px;
        width: auto;
        max-height: 84vh;
    }
    .chat-widget-body { height: auto; flex: 1; min-height: 38vh; max-height: 56vh; }
    body.chat-open .chat-widget-btn { display: none; }
}


/* ── Admin sign-in ────────────────────────────────────────── */
.login-wrap { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 24px; }
.login-card { width: 100%; max-width: 380px; }
.login-card__brand { margin-bottom: 22px; }
.login-card__brand img { height: 38px; width: auto; display: block; }
.login-error {
    background: var(--panel-raised);
    border-left: 2px solid var(--danger);
    color: var(--ink);
    padding: 11px 14px;
    font-size: 0.85rem;
    margin-bottom: 16px;
}

/* ── Admin flash messages ─────────────────────────────────── */
.flash {
    padding: 12px 16px;
    margin-bottom: 18px;
    font-size: 0.87rem;
    border: 1px solid var(--line);
    border-left-width: 2px;
    background: var(--panel);
}
.flash--ok  { border-left-color: var(--success); }
.flash--bad { border-left-color: var(--danger); }

/* ── Consultation image setting ───────────────────────────── */
.setting-row { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
.setting-row__thumb {
    width: 168px; height: 112px; object-fit: cover;
    border: 1px solid var(--line); flex-shrink: 0;
}
.setting-row__form { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; flex: 1; min-width: 240px; }

/* ── Doctor editor ────────────────────────────────────────── */
.doctor-edit {
    display: flex;
    gap: 20px;
    padding: 20px 0;
    border-bottom: 1px solid var(--line);
}
.doctor-edit:last-of-type { border-bottom: none; }
.doctor-edit__thumb {
    width: 96px; height: 96px; object-fit: cover; object-position: center 25%;
    border: 1px solid var(--line); flex-shrink: 0;
}
.doctor-edit__fields { flex: 1; min-width: 0; }
.doctor-edit__meta { display: flex; gap: 18px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 14px; }
.doctor-edit__actions { display: flex; gap: 10px; flex-wrap: wrap; }
.danger-btn:hover { border-color: var(--danger); color: var(--danger); }

.inline-field { display: flex; flex-direction: column; gap: 6px; }
.inline-field--grow { flex: 1; min-width: 200px; }
.inline-field span {
    font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--muted); font-weight: 600;
}
.inline-field input[type=number] { width: 80px; padding: 9px 10px; background: var(--bg); color: var(--ink); border: 1px solid var(--line); }
.inline-field input[type=checkbox] { width: 18px; height: 18px; accent-color: var(--accent); }

input[type=file] {
    font-family: inherit; font-size: 0.8rem; color: var(--muted);
    background: var(--bg); border: 1px solid var(--line); padding: 8px 10px; width: 100%;
}
input[type=file]::file-selector-button {
    font-family: inherit; font-size: 0.78rem; font-weight: 600;
    background: transparent; color: var(--ink);
    border: 1px solid var(--line-strong); padding: 6px 12px; margin-right: 12px; cursor: pointer;
}

.add-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }

@media (max-width: 700px) {
    .doctor-edit { flex-direction: column; }
    .doctor-edit__thumb { width: 100%; height: 160px; }
    .add-grid { grid-template-columns: 1fr; }
    .setting-row__thumb { width: 100%; height: 150px; }
}

/* ── Field helper text ────────────────────────────────────── */
.field-note {
    display: block;
    margin-top: 6px;
    font-size: 0.72rem;
    line-height: 1.5;
    color: var(--muted);
}

/* ── Consultation fee ─────────────────────────────────────── */
/* The naira mark sits inside the box rather than beside it, so the field
   reads as one control and nobody wonders whether to type the sign. */
.price-row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.price-row__input {
    display: flex;
    align-items: center;
    border: 1px solid var(--line);
    background: var(--bg);
}
.price-row__mark {
    padding: 0 4px 0 14px;
    color: var(--muted);
    font-size: 1.05rem;
    line-height: 1;
}
.price-row__input input {
    font-family: inherit;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--ink);
    background: transparent;
    border: 0;
    padding: 12px 14px 12px 4px;
    width: 150px;
}
.price-row__input input:focus { outline: none; }
.price-row__input:focus-within { border-color: var(--accent); }

/* ── Sponsor strip ────────────────────────────────────────── */
/* Sits above the nav on every public page. The chrome stays monochrome and
   the banner image carries whatever colour it wants: a sponsor should not be
   able to repaint the top of a medical site. */
.ad-bar {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    /* 16px matches the nav directly below, so the two stacked bands share
       one vertical rhythm instead of the strip reading as the tighter of
       the pair. The image cap comes down from 88px to pay for it: the
       strip's total height is a budget, and spending it on air rather
       than on a bigger banner costs the page nothing. */
    padding: 16px 44px;
    box-sizing: border-box;
    background: var(--panel);
    border-bottom: 1px solid var(--line);
}
.ad-bar a { display: block; line-height: 0; }
.ad-bar img { display: block; max-width: 100%; height: auto; max-height: 72px; }
.ad-bar__tag {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
}
.ad-bar__close {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}
.ad-bar__close:hover { color: var(--ink); }
.ad-bar__close .ico { width: 13px; height: 13px; }

/* ── Ad editor ────────────────────────────────────────────── */
.ad-edit {
    display: flex;
    gap: 20px;
    padding: 20px 0;
    border-bottom: 1px solid var(--line);
}
.ad-edit:last-of-type { border-bottom: none; }
.ad-edit__preview { width: 220px; flex-shrink: 0; }
.ad-edit__preview img {
    width: 100%;
    height: 74px;
    object-fit: contain;
    background: var(--bg);
    border: 1px solid var(--line);
}
.ad-edit__stats {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 10px;
    font-size: 0.72rem;
    color: var(--muted);
}
.ad-edit__fields { flex: 1; min-width: 0; }

/* Status is a word, not a colour alone: "Showing now" has to survive being
   read by someone who cannot tell the dot colours apart. */
.ad-state {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-weight: 600;
    color: var(--ink);
}
.ad-state::before {
    content: "";
    width: 6px;
    height: 6px;
    flex-shrink: 0;
    background: var(--muted);
}
.ad-state--live::before     { background: var(--success); }
.ad-state--upcoming::before { background: var(--muted); }
.ad-state--off::before      { background: var(--line-strong); }

@media (max-width: 700px) {
    .ad-edit { flex-direction: column; }
    .ad-edit__preview { width: 100%; }
    .ad-edit__stats { flex-direction: row; gap: 16px; flex-wrap: wrap; }
    .price-row__input input { width: 120px; }
    /* On a phone the banner is constrained by width, not by the height cap,
       so there is no image height to trade away. The strip simply grows by
       10px, which 31px of artwork badly needs. */
    /* 44px, same as desktop: at 38px the banner's right edge ran 2px under
       the close button's hit area, so a tap meant for the ad could dismiss it. */
    .ad-bar { padding: 12px 44px; }
    .ad-bar__tag { display: none; }
    .ad-bar img { max-height: 48px; }
}

/* ── Image cropper ────────────────────────────────────────── */
/* Frames the upload before it leaves the browser. Flat and sharp like the
   rest of the admin: the only rounded thing on screen would look borrowed. */
.crop-modal {
    position: fixed;
    inset: 0;
    z-index: 300;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(0, 0, 0, 0.72);
}
.crop-modal.is-open { display: flex; }
.crop-modal__panel {
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 22px;
    max-width: 780px;
    width: 100%;
    max-height: 100%;
    overflow-y: auto;
}
.crop-modal__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.crop-modal__head h3 { font-size: 1rem; }
.crop-modal__x {
    width: 32px; height: 32px; display: grid; place-items: center;
    padding: 0; border: 0; background: transparent; color: var(--muted); cursor: pointer;
}
.crop-modal__x:hover { color: var(--ink); }
.crop-modal__x .ico { width: 13px; height: 13px; }
.crop-modal__hint { font-size: 0.78rem; color: var(--muted); margin-bottom: 18px; line-height: 1.6; }

.crop-stage { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; }

/* The frame is the crop. Everything outside it is discarded, so it is shown
   at full strength while the surrounding image stays dimmed. */
.crop-frame {
    position: relative;
    overflow: hidden;
    background: var(--bg-deep);
    border: 1px solid var(--line-strong);
    cursor: grab;
    touch-action: none;
    flex-shrink: 0;
}
.crop-frame.is-dragging { cursor: grabbing; }
.crop-frame__img { position: absolute; top: 0; left: 0; will-change: transform; }
.crop-img { display: block; max-width: none; user-select: none; -webkit-user-drag: none; }

.crop-side { flex: 1; min-width: 170px; }
.crop-side__label {
    display: block;
    font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--muted); font-weight: 600; margin-bottom: 14px;
}
.crop-previews { display: flex; gap: 18px; flex-wrap: wrap; }
.crop-preview { display: flex; flex-direction: column; gap: 7px; }
.crop-preview__box { border: 1px solid var(--line); background-color: var(--bg-deep); }
.crop-preview span { font-size: 0.68rem; color: var(--muted); }

.crop-zoom { display: flex; align-items: center; gap: 14px; margin: 22px 0 20px; }
.crop-zoom span {
    font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--muted); font-weight: 600;
}
.crop-zoom input[type=range] {
    flex: 1;
    accent-color: var(--accent);
    height: 22px;
}
.crop-modal__actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }

/* Staged-crop confirmation beside the file input. */
.crop-done { display: block; margin-top: 6px; font-size: 0.72rem; color: var(--success); }

/* Recrop sits with the file input, not as a primary action. */
.recrop-btn {
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--ink);
    background: transparent;
    border: 1px solid var(--line-strong);
    padding: 7px 12px;
    margin-top: 8px;
    cursor: pointer;
}
.recrop-btn:hover { border-color: var(--accent); }

@media (max-width: 760px) {
    .crop-modal { padding: 12px; }
    .crop-modal__panel { padding: 16px; }
    .crop-stage { gap: 18px; }
    .crop-side { min-width: 100%; }
}

/* ── Missing photo ────────────────────────────────────────── */
/* Initials, not a broken image icon. Sized by the same rules as the <img>
   it stands in for, so the card keeps its shape until a photo is added. */
.photo-fallback {
    display: grid;
    place-items: center;
    background: var(--bg-deep);
    border: 1px solid var(--line);
    color: var(--muted);
    font-weight: 600;
    letter-spacing: 0.04em;
    user-select: none;
}
.doctor-profile .photo-fallback {
    width: 100%;
    aspect-ratio: 1 / 1;
    font-size: 2rem;
    margin-bottom: 16px;
}
.doctor-card .photo-fallback {
    width: 96px;
    height: 96px;
    font-size: 1.15rem;
    border-color: var(--line-strong);
    flex-shrink: 0;
}
.doctor-edit__thumb.photo-fallback { font-size: 1.3rem; }

/* ── Doctor assignment ────────────────────────────────────── */
.pending-row__act { display: flex; gap: 10px; align-items: center; flex-shrink: 0; flex-wrap: wrap; }
.assign-form { display: flex; gap: 6px; align-items: center; margin-top: 7px; }
.assign-form select { font-size: 0.74rem; padding: 5px 7px; min-width: 0; flex: 1; }
.assign-form__go { font-size: 0.72rem; padding: 5px 10px; white-space: nowrap; }

/* The assigned clinician, shown under the patient rather than in a column
   of its own: the consultations card is a third of the grid and a third
   column collided with the header. */
.cell-sub--doc { display: flex; align-items: center; gap: 6px; margin-top: 5px; color: var(--ink); }

/* Selects were never styled: the browser default is a rounded, light-grey
   control that reads as foreign in a flat dark panel. */
select {
    font-family: inherit;
    font-size: 0.8rem;
    color: var(--ink);
    background: var(--bg);
    border: 1px solid var(--line);
    border-radius: 0;
    padding: 8px 10px;
    max-width: 190px;
}
select:focus { outline: none; border-color: var(--accent); }

/* Secondary line inside a table cell, e.g. the time under a patient name. */
.cell-sub { display: block; font-size: 0.72rem; color: var(--muted); margin-top: 2px; }

@media (max-width: 700px) {
    .pending-row__act, .assign-form { width: 100%; }
    .pending-row__act select, .assign-form select { flex: 1; max-width: none; }
}

/* ── Setup instructions ───────────────────────────────────── */
.setup-steps { margin: 0; padding-left: 20px; color: var(--muted); font-size: 0.87rem; line-height: 1.7; }
.setup-steps li { margin-bottom: 12px; }
.setup-steps strong { color: var(--ink); }
.setup-steps a { color: var(--ink); }
.setup-steps code, .admin-content code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.82em;
    background: var(--bg-deep);
    border: 1px solid var(--line);
    padding: 1px 5px;
    color: var(--ink);
}
/* The redirect URI has to be copied exactly, so it gets its own line
   and is allowed to wrap rather than being clipped. */
.copy-line {
    display: block;
    margin-top: 8px;
    padding: 10px 12px !important;
    word-break: break-all;
    user-select: all;
}
