/*
 * The admin's OpenCart-shaped skin, in this project's black and white.
 *
 * Loaded through UNFOLD["STYLES"], which injects it after the theme's own
 * stylesheet on every admin page. That is the whole reason this is a stylesheet
 * and not a fork of django-unfold's CSS build: the theme stays a dependency you
 * can upgrade, and everything below is one file to re-check when you do.
 *
 * The rule this file follows, learned the hard way twice: only draw what the
 * theme does not already draw. Unfold puts a bottom border on every field row,
 * a box around the search area, and, the one that is easy to miss, a bordered
 * *wrapper* around inputs rather than a border on the input itself, which is
 * how the search box gets its icon and a price its "$". Bordering the input as
 * well therefore draws a second box inside the first.
 *
 * Adding a border here is not a neutral act. Look at the rendered markup for
 * the element first, and at its parent.
 *
 * Specificity: the theme styles with Tailwind utility classes, which are
 * single-class selectors. Rules here lead with an id (#content-main,
 * #result_list) so they win on specificity rather than on !important. Where a
 * utility genuinely cannot be outranked that way it is marked, and only there.
 */

:root {
    --oc-line: #dddddd;
    --oc-line-strong: #cccccc;
    --oc-head: #f9f9f9;
    --oc-hover: #f5f5f5;
    --oc-radius: 3px;

    /* The theme's own corner, read by every `rounded-default` element it
       renders: panels, buttons, inputs, the lot. Setting it here rather than
       restyling those elements one by one is the whole reason a single line
       squares off the entire admin. 6px is the theme's default and reads soft
       for a tool; 3px keeps the edge without going hard-cornered. */
    --border-radius: 3px;

    /* Tailwind's named steps, used by the handful of places that ask for a
       size rather than the default. Brought down in proportion so nothing
       ends up rounder than the panel containing it. */
    --radius-md: 3px;
    --radius-lg: 4px;
    --radius-xl: 5px;
}

html.dark {
    --oc-line: #374151;
    --oc-line-strong: #4b5563;
    --oc-head: rgba(255, 255, 255, 0.04);
    --oc-hover: rgba(255, 255, 255, 0.06);
}

/* ---- tables ------------------------------------------------------------ */
/* Ruled cells and a header band; the one place the theme genuinely draws less
   than a commerce admin needs. It separates rows with a single hairline and has
   no vertical rules at all, which is legible on four columns and hard work on
   nine. */

#result_list {
    border-collapse: collapse !important;   /* theme sets border-separate */
    border-spacing: 0 !important;
}

#result_list thead th {
    background: var(--oc-head);
    border: 1px solid var(--oc-line);
    font-weight: 600;
    padding: 0.625rem 0.75rem;
    vertical-align: middle;
}

#result_list tbody td,
#result_list tbody th {
    border: 1px solid var(--oc-line);
    padding: 0.625rem 0.75rem;
    vertical-align: middle;
}

/* Outer edges belong to the wrapper the theme draws around the table; the one
   with `lg:border lg:rounded-b-default`, which is the list's actual frame. The
   cells draw the grid inside it and nothing more.
 *
 * This was briefly reversed when the search panel's frame came off, on the
   assumption that the panel had been the only frame. It was not: the table has
   its own wrapper, so letting the cells draw an outer edge as well put two
   lines a pixel apart round the whole list. border-collapse cannot merge those
; they belong to different elements. */

#result_list thead th {
    border-top: 0;
}

#result_list thead th:first-child,
#result_list tbody tr > *:first-child {
    border-left: 0;
}

#result_list thead th:last-child,
#result_list tbody tr > *:last-child {
    border-right: 0;
}

#result_list tbody tr:last-child > td,
#result_list tbody tr:last-child > th {
    border-bottom: 0;
}

/* The row under the cursor. OpenCart's clearest affordance, and the theme has
   none, on a long list there is nothing tying a name to the price beside it. */
#result_list tbody tr:hover > td,
#result_list tbody tr:hover > th {
    background: var(--oc-hover);
}

/* ---- the save bar ------------------------------------------------------ */
/* OpenCart pins save to the top right of the page. The theme puts the save row
   at the foot of the form, which on a tabbed form means scrolling past whichever
   tab you are on to reach it. Made sticky rather than moved: moving it would
   fight the theme's layout on every screen. The border is the only thing
   separating it from the content scrolling under it, so it stays. */

/* :not(button) because the theme puts this class on the login screen's submit
   button as well as on the change form's bar. Painting a button the bar's
   background gives it white on white; the label is still there, just
   invisible. Only the bar is a container, so only the bar is styled. */
.submit-row:not(button) {
    background: #fff;
    border-top: 1px solid var(--oc-line);
    bottom: 0;
    position: sticky;
    z-index: 20;
}

html.dark .submit-row:not(button) {
    background: #111827;
}

/* ---- movement ---------------------------------------------------------- */
/* Everything that changes appearance on hover or click does so over a beat
   rather than between frames. An instant change reads as a glitch: nothing ties
   the thing you did to the thing that changed. These are short on purpose:
   long enough to be seen as a movement, short enough that nobody waits for it.
 *
 * The theme already eases its own controls; these are the surfaces it leaves
 * to the browser, which by default has no easing at all. */

#result_list tbody tr > td,
#result_list tbody tr > th {
    transition: background-color 120ms ease-out;
}

/* Row controls and anything else with a border that answers the cursor. */
#result_list a,
#content-main .rounded-default {
    transition: background-color 120ms ease-out,
                border-color 120ms ease-out,
                color 120ms ease-out;
}

/* Panels that appear when a tab is chosen. The strip itself already eases its
   underline; without this the panel under it swaps between frames and the two
   halves of one gesture look unrelated. */
.tab-wrapper {
    animation: oc-tab-in 140ms ease-out;
}

@keyframes oc-tab-in {
    from { opacity: 0; transform: translateY(2px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Respect a reader who has asked the system for less movement. Not optional:
   for some people this is a vestibular symptom, not a preference. */
@media (prefers-reduced-motion: reduce) {
    #result_list tbody tr > td,
    #result_list tbody tr > th,
    #result_list a,
    #content-main .rounded-default,
    /* The sidebar fold, which is a grid-row transition; see
       templates/unfold/helpers/app_list.html. */
    #nav-sidebar-apps .grid {
        transition: none;
    }

    .tab-wrapper {
        animation: none;
    }
}

/* ---- the sidebar edge -------------------------------------------------- */
/* The sidebar is told apart from the page by being a different surface, not by
   a rule down its side. A border is a third thing on screen doing the job the
   two backgrounds already do between them, and once the separators inside the
   nav are gone, the one down the edge is the only line left, which makes it
   look like an accident rather than a choice.
 *
 * The tint is deepened a little at the same time: with no border, the panel has
 * to hold its own edge, and the theme's default sits too close to the white of
 * the content beside it to read as a separate surface on a bright screen. */

#nav-sidebar {
    background: #fafafa;
    border-right: 0;
}

html.dark #nav-sidebar {
    background: #0f1115;
    border-right: 0;
}

#nav-sidebar-inner {
    background: transparent;
}

/* No rule under the wordmark. It was the last line left in a sidebar whose
   section separators have all gone, and a single divider with nothing to
   match it reads as something forgotten rather than as structure. The logo is
   set apart by its own space instead. */
#nav-sidebar-inner > div:first-child {
    border-bottom: 0;
    margin-bottom: 0.75rem;
}

/* ---- the size of that wordmark ----------------------------------------- */
/* The theme draws SITE_LOGO at 32px. That is a favicon's worth of room for a
   mark with the shop's name written inside it: at that height the words stop
   being words and the whole thing reads as a smudge, in a sidebar 288px wide
   that was spending almost none of it.
 *
 * The row has to be told as well as the image. The theme fixes both the header
 * and the block inside it with h-[65px] and h-[64px] utilities, so a taller
 * mark alone would just overflow them. Height goes to auto with a floor rather
 * than a second fixed number, so the row still fits whatever a future logo of a
 * different shape needs. */
#nav-sidebar-inner > div:first-child,
#nav-sidebar-inner > div:first-child > div:first-child {
    height: auto;
    min-height: 96px;
}

#nav-sidebar-inner > div:first-child img {
    height: 64px;
}

/* ---- where you are in the sidebar -------------------------------------- */
/* Three states, because there are three questions: which section is open, what
   is in it, and which of those am I looking at. The theme answers only the last
   one, so an open section looked the same as a closed one with rows under it.
 *
 * All three are carried by surface, not by hue. This admin has no accent colour
 * to spend, the palette is greys, so depth does the work a blue would do in
 * OpenCart, and it keeps working in dark mode where a tint would not.
 *
 * The shape follows OpenCart's: full-width bands, square edges, rows tight
 * enough that a whole section is readable without scrolling. The theme's own
 * spacing is built for a shorter menu than this one.
 *
 * `.nav-section-open` is set by Alpine on the heading; CSS cannot read the
 * variable itself. See templates/unfold/helpers/app_list.html. */

/* Section headings: full width, no inset, no rounding. */
#nav-sidebar-apps h2 {
    border-radius: 0;
    margin: 0;
    padding: 0.5rem 1rem;
    transition: background-color 120ms ease-out, color 120ms ease-out;
}

/* Two colours in the sidebar, and only two.
 *
 * The open section is one of them: the heading and the rows under it share a
 * single surface, because an open section is one thing and shading its lid
 * differently from its contents only made the strip look busy.
 *
 * The row you are on is the other. It is the one place a second colour earns
 * its keep, so it gets a real step away from the section around it; far
 * enough to find without scanning, and nowhere near the white of the content
 * area, which is what made an earlier version read as a hole in the sidebar. */
#nav-sidebar-apps h2.nav-section-open {
    background: #eeeef2;
    color: var(--color-font-important-light, #18181b);
}

html.dark #nav-sidebar-apps h2.nav-section-open {
    background: #191d24;
}

/* The rows inside an open section, as one band.
 *
 * padding: 0 is not cosmetic. The fold works by taking the grid row to 0fr,
 * which zeroes the list's *content* height: padding is not part of that, so
 * any vertical padding here survives the collapse and leaves a grey stripe
 * under every closed section. */
#nav-sidebar-apps .nav-section-items {
    background: #eeeef2;   /* the same surface as the heading above it */
    border-radius: 0;
    margin: 0;
    padding: 0;
}

html.dark #nav-sidebar-apps .nav-section-items {
    background: #191d24;
}

/* Rows: tighter than the theme's 38px, square, full width. */
#nav-sidebar-apps ol {
    gap: 0;
    padding-left: 0;
    padding-right: 0;
}

#nav-sidebar-apps ol a {
    border-radius: 0;
    height: 34px;
    margin: 0;
    padding-left: 2rem;
    padding-right: 1rem;
}

/* The row you are actually on. Strengthened over the theme's, which is a tint
   so light it disappears once the group behind it has one of its own. */
/* The second colour: the row you are on. */
#nav-sidebar-apps ol a.active {
    background: #d9d9e0;
    color: var(--color-font-important-light, #18181b);
    font-weight: 600;
}

#nav-sidebar-apps ol a.active .material-symbols-outlined {
    color: var(--color-font-important-light, #18181b);
}

html.dark #nav-sidebar-apps ol a.active {
    background: #2b313b;
    color: #f4f4f5;
}

html.dark #nav-sidebar-apps ol a.active .material-symbols-outlined {
    color: #f4f4f5;
}

/* Top-level rows that belong to no section (Dashboard, All applications)
   line up with the headings rather than with the indented rows. */
#nav-sidebar-apps > div > ol:not(.nav-section-items) a {
    padding-left: 1rem;
}

/* Sections stack directly on one another. The theme spaces them apart, which
   suits a menu of three groups and leaves this one looking like a list of
   unrelated cards. */
#nav-sidebar-apps > div {
    margin-bottom: 0;
}



/* ---- card headers ------------------------------------------------------ */
/* A titled card gets a header band, the way a panel does in OpenCart. The
   theme gives the title a bottom border and nothing else, so on a white card
   the heading and the content it heads sit on the same surface and the border
   is doing all the work.
 *
 * `.oc-card-title` is passed as `title_class` at each call site rather than
   guessed at with a structural selector; the component supports it, and a
   selector like "the card's first div" breaks the moment the markup moves. */

.oc-card-title {
    background: var(--oc-head);
}

html.dark .oc-card-title {
    background: rgba(255, 255, 255, 0.03);
}

/* ---- the fold, timed --------------------------------------------------- */
/* Kept here rather than in Tailwind classes on the element so the whole
   movement is one place to tune.
 *
 * 320ms and a symmetrical curve. The first attempt used 200ms with ease-out,
 * which is the curve for something arriving: applied to a close it means the
 * section races away and stops dead. ease-in-out reads as the same gesture in
 * both directions, and at this height 200ms is under the threshold where the
 * eye follows the movement rather than just noticing the result. */

#nav-sidebar-apps .nav-section-fold {
    transition: grid-template-rows 320ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* The rows fade slightly behind the slide. Without it the text is legible at
   full strength while the section is still a few pixels tall, which reads as
   the list being cropped rather than opening. Faster on the way in than the
   slide, slower on the way out, so the rows are gone before the gap closes. */
#nav-sidebar-apps .nav-section-fold .nav-section-items {
    opacity: 0;
    transition: opacity 160ms ease-in;
}

#nav-sidebar-apps .nav-section-fold.is-open .nav-section-items,
#nav-sidebar-apps .nav-section-fold[data-open-on-load] .nav-section-items {
    opacity: 1;
    transition: opacity 240ms ease-out 60ms;
}

@media (prefers-reduced-motion: reduce) {
    #nav-sidebar-apps .nav-section-fold,
    #nav-sidebar-apps .nav-section-fold .nav-section-items {
        transition: none;
    }
}

/* ---- the search bar stands alone --------------------------------------- */
/* The theme wraps the search box and the Filters button in a bordered panel,
   then pulls the table up into it with a negative margin so the two read as one
   unit. That is a second frame around a table that already has one, and on a
   page whose only content is a list it is a box around a box.
 *
 * The panel's border and its tuck are removed, so the search sits free above
 * the list and the list is the only bordered thing on the page. The tuck is the
 * part that matters: leaving `-mb-8` behind without the border would pull the
 * table up under nothing and clip its top edge.
 *
 * Selected by the padding utility that is unique to this element, since the
 * theme gives it no id or name of its own. */

#changelist [class*="pb-11"] {
    border: 0 !important;      /* theme sets lg:border */
    margin-bottom: 1rem !important;   /* theme sets lg:-mb-8 */
    padding: 0 !important;     /* theme sets lg:p-3 lg:pb-11 */
}

/* ---- the change form's tab strip --------------------------------------- */
/* Real CSS, not utility classes: the theme's Tailwind is built ahead of time
   from its own source, so any class this project invents; `[&>.active]:...`
   and the like; is absent from the stylesheet and silently does nothing. That
   is exactly how the active tab ended up with no indicator at all.
 *
 * See templates/admin/form_tabs.html, which draws the strip. */

#tabs-items > a {
    border-bottom: 2px solid transparent;
    color: var(--color-font-subtle-light, #71717a);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.875rem;
    font-weight: 500;
    margin-bottom: -1px;
    padding: 0.625rem 0.875rem;
    transition: border-color 120ms ease-out, color 120ms ease-out;
    white-space: nowrap;
}

#tabs-items > a:hover {
    border-bottom-color: #c4c4c8;
    color: var(--color-font-important-light, #18181b);
}

#tabs-items > a.active {
    border-bottom-color: #18181b;
    color: #18181b;
    font-weight: 600;
}

html.dark #tabs-items > a {
    color: var(--color-font-subtle-dark, #a1a1aa);
}

html.dark #tabs-items > a:hover {
    border-bottom-color: #4b5563;
    color: #f4f4f5;
}

html.dark #tabs-items > a.active {
    border-bottom-color: #f4f4f5;
    color: #f4f4f5;
}

/* ---- the filter drawer ------------------------------------------------- */
/* The classes Alpine swaps on and off the drawer and its scrim. Alpine only
   adds the names; the stylesheet has to define them, and Tailwind's own cannot
   be borrowed; the theme's CSS is built from the theme's source, so a utility
   it never used does not exist. See the template.
 *
 * Out is quicker than in: by the time you are closing it you know what you
   asked for, and waiting to get back to the list is the annoying half. */

.oc-drawer-in {
    transition: opacity 200ms ease-out, transform 200ms ease-out;
}

.oc-drawer-out {
    transition: opacity 140ms ease-in, transform 140ms ease-in;
}

.oc-faded {
    opacity: 0;
}

.oc-offscreen {
    opacity: 0;
    transform: translateX(1.5rem);
}

/* The panel's own arrival. A keyframe, not a transition: it is drawn with its
   wrapper rather than toggled, so there is no "before" state to move from. */
.oc-drawer-panel {
    animation: oc-drawer-slide 220ms cubic-bezier(0.4, 0, 0.2, 1);
}

@keyframes oc-drawer-slide {
    from { opacity: 0; transform: translateX(1.5rem); }
    to   { opacity: 1; transform: translateX(0); }
}

.oc-shown {
    opacity: 1;
    transform: translateX(0);
}

@media (prefers-reduced-motion: reduce) {
    .oc-drawer-in,
    .oc-drawer-out {
        transition: none;
    }

    .oc-offscreen {
        transform: none;
    }

    .oc-drawer-panel {
        animation: none;
    }
}


/* ---------------------------------------------------------------------------
   Password boxes
   ---------------------------------------------------------------------------
   The show/hide toggle password-eye.js hangs inside the field. The wrapper it
   builds is what carries `position: relative`, not the input, so the icon sits
   over the box rather than beside it, and the theme is pinned light, so there
   is no dark pair to keep in step here.
*/

.oc-pw {
    position: relative;
    display: block;
}

/* Room for the icon. Set here rather than by adding a Tailwind padding class
   in the script: the theme ships a prebuilt stylesheet, so only the utilities
   django-unfold itself uses exist in it. Outranks the input's own `px-3` on
   specificity, which is how the rest of this file wins too. */
.oc-pw input {
    padding-right: 2.5rem;
}

.oc-pw-toggle {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    padding: 0;
    border: 0;
    background: none;
    color: #999999;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
}

.oc-pw-toggle:hover {
    color: #333333;
}


/* ---------------------------------------------------------------------------
   Merge tags
   ---------------------------------------------------------------------------
   Two blocks from one call. The list of meanings stays in the form; the button
   grid is lifted into the floating panel below by merge-tags.js.
*/

.oc-tag-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 13px;
    color: #666666;
}

.oc-tag-list code {
    padding: 1px 4px;
    border-radius: var(--oc-radius);
    background: var(--oc-head);
    color: #333333;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
}

.oc-tags {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Laid out with flex, which an unqualified [hidden] cannot beat. */
.oc-tags[hidden] {
    display: none;
}

.oc-tags-hint {
    margin: 0;
    font-size: 13px;
    color: #666666;
}

/* Two across. The panel is sized so a pair of them sits comfortably on a row,
   which keeps nineteen shortcuts to ten rows instead of nineteen. */
.oc-tag-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
}

.oc-tag {
    width: 100%;
    padding: 4px 6px;
    border: 1px solid var(--oc-line-strong);
    border-radius: var(--oc-radius);
    background: #ffffff;
    color: #333333;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    line-height: 1.5;
    text-align: center;
    cursor: pointer;
}

.oc-tag:hover {
    border-color: #999999;
    background: var(--oc-hover);
}

/* The button is the thing being clicked all day, so it gets a real pressed
   state rather than only a hover. */
.oc-tag:active {
    background: var(--oc-line);
}


/* ---------------------------------------------------------------------------
   The shortcuts panel
   ---------------------------------------------------------------------------
   merge-tags.js pairs the message box with the button grid in one row. Flex
   with the default `stretch` is what gives them a common height: the panel is
   as tall as ten rows of buttons, and the textarea, which would otherwise
   stop at its `rows` height: grows to meet it. That is also a better box to
   write an email in than the short one the theme ships.
*/

.oc-compose {
    display: flex;
    align-items: stretch;
    gap: 12px;
    max-width: 56rem;
}

.oc-compose > textarea {
    /* Beats the theme's `max-w-4xl`, which would otherwise cap the box at the
       full width of the row and leave the panel nowhere to sit. */
    flex: 1 1 auto;
    max-width: none;
    /* `rows` sets an intrinsic height that stretch alone will not override. */
    height: auto;
    align-self: stretch;
}

.oc-plate {
    flex: 0 0 340px;
    display: flex;
    flex-direction: column;
    min-height: 0;
    border: 1px solid var(--oc-line-strong);
    border-radius: var(--oc-radius);
    background: #ffffff;
}

/* The panel is laid out with flex, which an unqualified [hidden] cannot beat. */
.oc-plate[hidden] {
    display: none;
}

.oc-plate-head {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 6px 6px 12px;
    border-bottom: 1px solid var(--oc-line);
    background: var(--oc-head);
    border-radius: var(--oc-radius) var(--oc-radius) 0 0;
}

.oc-plate-title {
    font-size: 13px;
    font-weight: 600;
    color: #333333;
}

.oc-plate-close {
    flex: none;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--oc-radius);
    background: none;
    color: #666666;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
}

.oc-plate-close:hover {
    border-color: var(--oc-line-strong);
    background: #ffffff;
    color: #333333;
}

.oc-plate-body {
    /* min-height:0 so a long list scrolls inside the panel rather than making
       the row, and with it the message box, taller than the screen. */
    min-height: 0;
    overflow-y: auto;
    padding: 12px;
}

/* The button that brings it back, under the message box. */
.oc-plate-open {
    margin-top: 8px;
    padding: 4px 10px;
    border: 1px solid var(--oc-line-strong);
    border-radius: var(--oc-radius);
    background: #ffffff;
    color: #333333;
    font-size: 12px;
    line-height: 1.5;
    cursor: pointer;
}

.oc-plate-open:hover {
    border-color: #999999;
    background: var(--oc-hover);
}

.oc-plate-open[hidden] {
    display: none;
}

/* Narrow windows: the two stack, and equal height stops meaning anything. */
@media (max-width: 1100px) {
    .oc-compose {
        flex-direction: column;
    }

    .oc-plate {
        flex: none;
    }
}

/* ---------------------------------------------------------------------------
   The new customer offer

   One sentence over the form, saying what a person signing up will be given.
   It sits directly under the switch because that is what it answers: the whole
   screen is a promise, and this is the promise in words. signup-offer.js writes
   it; with JavaScript off it is never inserted and nothing here applies.
   --------------------------------------------------------------------------- */

.oc-offer {
    margin: 0;
    padding: 14px 16px;
    border-top: 1px solid var(--oc-line);
    background: var(--oc-head);
    color: #333333;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.5;
}

/* Off is a state worth reading as one, not a sentence in the same voice as a
   live offer. */
.oc-offer-off {
    font-weight: 400;
    font-style: italic;
    color: #777777;
}

/* Editable while the offer is off, since setting one up before turning it on
   is ordinary; dimmed so the page says which it is without being read. */
.oc-offer-idle {
    opacity: 0.55;
}

@media (prefers-color-scheme: dark) {
    .oc-offer {
        color: #e5e7eb;
    }

    .oc-offer-off {
        color: #9ca3af;
    }
}
