/* ========================
   GLOBAL STYLES
   ======================== */

:root {
    --primary-color: #FF385C;
    --secondary-color: #FF385C;
    --dark-color: #222222;
    --light-color: #F7F7F7;
    --text-color: #222222;
    --border-color: #DDDDDD;
    --shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

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

html {
    scroll-behavior: smooth;
}

body {
    font-family: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
    color: var(--text-color);
    background-color: #ffffff;
    line-height: 1.6;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px;
}

/* ========================
   NAVBAR
   ======================== */

.navbar {
    background-color: #fff;
    box-shadow: var(--shadow);
    position: sticky;
    top: 0;
    z-index: 100;
}

.navbar .container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 15px 20px;
}

.navbar-brand h1 {
    font-size: 24px;
    color: var(--primary-color);
}

.navbar-brand a {
    text-decoration: none;
    color: inherit;
}

.navbar-menu {
    display: flex;
    list-style: none;
    gap: 30px;
    align-items: center;
}

.navbar-menu a {
    text-decoration: none;
    color: var(--text-color);
    font-weight: 500;
    transition: color 0.3s;
}

.navbar-menu a:hover {
    color: var(--primary-color);
}

.btn-logout {
    background-color: var(--primary-color);
    color: white !important;
    padding: 8px 16px;
    border-radius: 4px;
    transition: background-color 0.3s;
}

.btn-logout:hover {
    background-color: #E74C3C;
}

/* ========================
   MESSAGES
   ======================== */

/* The container is in base.html unconditionally so live notification toasts
   have somewhere to go; with nothing in it, it must not push the page down. */
.messages:empty { display: none; margin: 0; padding: 0; }

/* Shown when a live region had something new but somebody was typing in it,
   or reading an expanded note, or holding a confirm dialog open. The update
   waits behind this rather than taking their work with it. */
.live-pending {
    display: block;
    width: 100%;
    margin: 0 0 10px;
    padding: 8px 12px;
    border: 1px solid #bee5eb;
    border-radius: 6px;
    background: #d1ecf1;
    color: #0c5460;
    font-size: 0.85rem;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}
.live-pending:hover { background: #c3e6ea; }

.messages {
    max-width: 1200px;
    margin: 1rem auto;
    padding: 0 2rem;
    position: relative;
    z-index: 5;
}
@media (max-width: 720px) {
    .messages { padding: 0 1rem; }
}

.alert {
    padding: 15px 20px;
    border-radius: 4px;
    margin-bottom: 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.alert-success {
    background-color: #d4edda;
    color: #155724;
    border: 1px solid #c3e6cb;
}

.alert-error {
    background-color: #f8d7da;
    color: #721c24;
    border: 1px solid #f5c6cb;
}

.alert-info {
    background-color: #d1ecf1;
    color: #0c5460;
    border: 1px solid #bee5eb;
}

.close-alert {
    background: none;
    border: none;
    font-size: 20px;
    cursor: pointer;
    color: inherit;
}

/* ========================
   BUTTONS
   ======================== */

/* Tap targets: 44px is the size a thumb reliably hits, and most of this
   site's traffic is a phone. Buttons, form controls and the small-button
   variant were rendering between 16px and 42px tall, which reads as "the
   site ignored my tap" rather than as a design choice. */
/* .btn used to be declared twice: here, and again in base.html's inline
   <style>, which loads later and so won this file's padding, radius and font.
   But min-height and line-height only ever existed here, so the inline block
   kept them without knowing it -- leaving a .btn-sm anchor 32.8px of content
   inside a 44px box. inline-block drops all 11.2px of that below the text, so
   "View" sat 12px above its own centre. The values below are the ones that
   were already winning in the browser; the flex centring is what is new. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    line-height: 1.25;
    padding: 0.6rem 1.5rem;
    border-radius: 10px;
    font-family: 'Plus Jakarta Sans', sans-serif;
    font-size: 0.9rem;
    text-decoration: none;
    font-weight: 600;
    transition: all 0.2s;
    border: none;
    cursor: pointer;
    text-align: center;
}

.btn-primary {
    background-color: var(--primary-color);
    color: white;
}

.btn-primary:hover {
    background-color: #E74C3C;
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3);
}

.btn-secondary {
    background-color: var(--secondary-color);
    color: white;
}

.btn-secondary:hover {
    background-color: #00B8A9;
    transform: translateY(-2px);
}

/* Full-width buttons used to be spelled as an inline
   style="width:100%;text-align:center;display:block" on the element itself. An
   inline style beats every stylesheet, so that display:block quietly overrode
   .btn's inline-flex: the box stopped being a flex container, align-items had
   nothing left to centre, and the 44px floor dropped all its slack below the
   text again. The rule was correct and the markup cut it, one element at a
   time, on every detail page. A class can be overridden and inspected; an
   inline style can do neither, so the full-width case lives here. */
.btn-block {
    display: flex;
    width: 100%;
}

.btn-small,
.btn-sm {
    /* Smaller than a .btn, never smaller than a thumb. */
    min-height: 44px;
    padding: 0.4rem 1rem;
    font-size: 0.82rem;
    border-radius: 8px;
}

/* Footer links sat at 16px tall, stacked, with nothing between them: a miss
   lands on the one above. The padding is the target; the text is unchanged. */
.footer a {
    display: inline-block;
    padding: 6px 2px;
}

/* ========================
   MAIN CONTENT
   ======================== */

.main-content {
    min-height: calc(100vh - 200px);
    /* --nav-height set in base.html (108px desktop / 68px mobile). One source
       of truth so bumping the logo or nav height never re-introduces clipping. */
    padding-top: var(--nav-height, 108px);
}
/* The marketplace header (mockup) is a solid two-row bar, not a transparent
   overlay, so the hero/content sits BELOW it — no negative pull-up. The
   .main-content padding-top (= --nav-height) already provides the clearance. */

/* ========================
   FOOTER
   ======================== */

.footer {
    background-color: var(--dark-color);
    color: white;
    text-align: center;
    padding: 40px 20px;
    margin-top: 60px;
}

.footer p {
    margin: 10px 0;
}

/* ========================
   FORMS
   ======================== */

form {
    max-width: 600px;
    margin: 0 auto;
}

.form-group {
    margin-bottom: 20px;
}

label {
    display: block;
    margin-bottom: 8px;
    font-weight: 600;
    color: var(--text-color);
}

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="password"],
input[type="number"],
input[type="date"],
select,
textarea {
    width: 100%;
    min-height: 44px;
    padding: 12px;
    border: 1px solid var(--border-color);
    border-radius: 4px;
    font-size: 14px;
    font-family: inherit;
}

/* Plain <select> elements otherwise fall back to each browser's native
   combobox chrome (a stacked up/down glyph on some platforms), which reads
   as unstyled next to the text/number inputs above. A single custom chevron
   keeps every dropdown on the site visually consistent with the rest of the
   form controls. */
select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    padding-right: 36px;
    background-color: #fff;
    background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='5 8 10 13 15 8'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 16px 16px;
    cursor: pointer;
}

select:invalid,
select option[value=""] {
    color: #767676;
}

/* ── Checkbox pill grid ──────────────────────────────────────────────────
   "Tick every one that applies" — vendor registration's category picker and
   the product form's Service Category picker. Shared rather than inlined in
   one template, because two copies of a control this fiddly drift apart: the
   native box is taken out of the flow (never display:none, which would take
   it out of the tab order with it) and the pill beside it carries the whole
   appearance, so hover, checked and keyboard focus all have to agree.
   Markup: .checkbox-grid > label.check-option > input + span.check-pill */
.checkbox-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 8px;
}

.check-option {
    display: block;
    margin: 0;
    cursor: pointer;
}

.check-option input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.check-pill {
    display: flex;
    align-items: center;
    gap: 9px;
    min-height: 44px;
    padding: 9px 12px;
    border: 1px solid #ddd;
    border-radius: 10px;
    font-weight: 600;
    font-size: .9rem;
    color: #444;
    transition: border-color .15s ease, background-color .15s ease;
}

.check-pill:before {
    content: "";
    flex: 0 0 18px;
    height: 18px;
    border: 1.5px solid #c4c4c4;
    border-radius: 5px;
    background: #fff;
}

.check-option:hover .check-pill {
    border-color: #aaa;
}

.check-option input:checked + .check-pill {
    border-color: var(--primary-color);
    background: #fff6f8;
    color: var(--primary-color);
}

.check-option input:checked + .check-pill:before {
    background: var(--primary-color);
    border-color: var(--primary-color);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.5 3.5L13 5'/%3E%3C/svg%3E");
    background-size: 14px;
    background-position: center;
    background-repeat: no-repeat;
}

.check-option input:focus-visible + .check-pill {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}

/* A phone fits one pill per line well before the 190px track does. */
@media (max-width: 420px) {
    .checkbox-grid {
        grid-template-columns: 1fr;
    }
}

button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 3px solid rgba(255, 56, 92, 0.35);
    outline-offset: 2px;
}

textarea {
    resize: vertical;
    min-height: 120px;
}

input:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px rgba(255, 107, 107, 0.1);
}

/* ========================
   RESPONSIVE
   ======================== */

@media (max-width: 768px) {
    .navbar-menu {
        flex-direction: column;
        gap: 15px;
        align-items: flex-start;
    }

    .container {
        padding: 0 15px;
    }

    input,
    select,
    textarea {
        font-size: 16px;
    }
}

/* A file the visitor already sent, kept across a failed submit. Styled as a
   confirmation rather than an error: the file is fine, it is some other field
   that needs fixing, and a red note here would send them to re-pick it. */
.upload-held {
  display: block;
  margin-top: 0.35rem;
  padding: 0.4rem 0.6rem;
  border-radius: 6px;
  background: #edf7ed;
  border: 1px solid #c9e6c9;
  color: #256029;
  font-size: 0.85em;
  line-height: 1.4;
}

.upload-held strong {
  word-break: break-all;
}

/* ========================
   VISITOR-TYPED TEXT
   ========================

   A review, a booking note or an enquiry is typed by a stranger, and some of
   them type 900 characters without pressing space. CSS will not break inside a
   "word", so that one token set the width of the card it sat in and pushed the
   whole page sideways — the bug reported on My Bookings and on the vendor
   page's Recent Reviews. Two rules fix it and they belong together:

   * the site-wide `overflow-wrap` below is the safety net. It only acts when a
     word would otherwise overflow, so ordinary prose wraps exactly as before,
     and it covers every surface including ones added later.
   * `.user-text` is the deliberate treatment for a block of typed text: it
     honours the line breaks the visitor typed (the templates render these
     fields raw, so without `pre-line` a nine-line note arrived as one
     paragraph) and caps the block at nine lines with a "Show more" toggle
     added by user-text.js. Nine is both limits: a form accepts nine lines and
     nine is what a card shows, so a review can never occupy more of the page
     than the next review does. Text past the ninth line — a long line that
     wrapped — is one click away behind the toggle, not lost.

   The clamp is applied by the script, not by this stylesheet, so a visitor
   with JavaScript off sees the whole note rather than ten lines with no way
   to reach the rest. */

/* ========================
   THE hidden ATTRIBUTE
   ========================

   `hidden` is how every panel, tray and inline error on this site is shown
   and hidden from script, and it silently does nothing the moment the element
   also has a class that sets `display`. The UA rule is `[hidden]{display:none}`
   at specificity (0,1,0), and an author rule beats a UA rule outright — so
   `.cmp-bar { display:flex }` won, `bar.hidden = true` changed an attribute
   nobody was listening to, and the compare tray stayed on screen showing a
   selection the visitor had just cleared.

   Six elements had already been patched one at a time with their own
   `.thing[hidden] { display:none }` (the help assistant's even carries a note
   explaining why). Those are left where they are — they are harmless and they
   document the trap — but patching the seventh after it is reported is not a
   strategy. This is the rule that makes `hidden` mean hidden everywhere,
   including on elements added after today.

   `!important` is not decoration here: `[hidden]` ties with a single class on
   specificity, so without it source order decides, and a page's own <style>
   block always comes after this file. Nothing on this site wants an element
   that is `hidden` and still painted. */
[hidden] {
  display: none !important;
}

body {
  overflow-wrap: break-word;
}

.user-text {
  white-space: pre-line;
  /* `anywhere` rather than `break-word`: inside a flex or grid child only
     `anywhere` also shrinks the box's min-content width, which is what stops
     the card itself from being stretched by the text. */
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
}

.user-text.is-clamped {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 9;
  line-clamp: 9;
  overflow: hidden;
}

.user-text-toggle {
  display: inline-block;
  margin-top: 0.35rem;
  padding: 0;
  border: none;
  background: none;
  color: var(--primary-color, #FF385C);
  font: inherit;
  font-size: 0.85em;
  font-weight: 600;
  cursor: pointer;
}

.user-text-toggle:hover {
  text-decoration: underline;
}

/* The line-count hint under a textarea that has reached its limit. */
.text-line-limit {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.8em;
  line-height: 1.4;
  color: #8a6d3b;
}

/* A name in a flex row. `overflow-wrap` alone is not enough inside a flex
   child: the box keeps its min-content width and pushes its siblings out, so
   a 27-character username ran the star rating past the edge of the card on a
   phone. `min-width:0` is the half that lets it shrink. */
.user-name {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ========================
   CARD GRIDS
   ========================

   A row of cards must wrap onto the next row, never widen the page. Two
   defaults work against that and both have been seen doing it on this site:

   * A grid or flex item's automatic minimum size is its *content*, so one
     child too wide to fit — a wall of characters, an image, a table — makes
     the track wider than the page instead of being made to fit. `min-width:0`
     on both the grid and its children is what lets them shrink. Without it a
     single review pushed the vendor page's sidebar off the screen and
     stretched every card above it, because the `2fr` column grew to hold it.
   * The second value of `minmax(280px, 1fr)` is a *floor*, not a preference,
     so on a phone narrower than the floor the card is laid out at 280px
     whatever the column measures. A 320px phone leaves 256px of content
     width between the container's padding: the card overran it by 24px into
     the gutter, and below a 312px viewport the page itself began to scroll.
     `min(280px, 100%)` keeps the 280px intent where there is room to honour
     it and gives way where there is not. */
.grid-2,
.grid-3,
.grid-4 {
  min-width: 0;
}

.grid-2 > *,
.grid-3 > *,
.grid-4 > * {
  min-width: 0;
}
