/*
  Forasak — the reading surface.

  Design notes, so later edits stay coherent:

  * This is a TOOL, scanned on a phone in a spare minute, not an article. So
    the craft goes into information density and status legibility rather than
    into a hero. Every card must answer "is this for me, is it fresh, where do
    I click" in one glance.
  * Palette is a deep teal-green accent on neutrals biased very slightly green,
    so the greys read as chosen rather than inherited. Semantic colours (fresh
    / stale / failed) are deliberately separate from the accent, otherwise a
    green accent would make everything look "ok".
  * TWO WEBFACES, SERVED BY US, NEVER BY A CDN. This used to be system fonts
    only, for a reason that still holds: the backend serves this
    offline-capable and CDN-free, and a <link> to a font host would put a
    third-party request in front of the first paint and leave the page
    faceless whenever the connection drops. So both faces live in
    /static/fonts and are precached by the service worker.

    Newsreader carries the headings. Nothing else in the design does as much
    to stop this looking like every other dashboard, and a serif is what
    makes a list of jobs read as an edition rather than a table.

    IBM Plex Sans Arabic carries Arabic. That one is not decoration: half
    this product's readers read Arabic, and they were being served Tahoma,
    a face nobody would choose. Only the Arabic ranges are fetched — Latin
    inside an Arabic page falls back to the system sans, as it always did.

    Latin BODY text is still the system stack. It costs nothing, it is what
    every phone renders best, and it pairs with the serif perfectly well.
    The old note said:
    Segoe UI and Tahoma both render Arabic acceptably on the devices these
    users actually have, and a data-URI webfont would cost weight for nothing.
  * Content is bilingual and mixed per card, so text uses dir="auto" at the
    element level. The UI chrome flips via [dir] on <html>; card text does not.
*/

/* ------------------------------------------------------------------ type
   Self-hosted, woff2, ~200 KB for all four and cached after the first
   visit. font-display:swap on every one: text paints immediately in the
   fallback and swaps when the face lands, so a slow connection costs a
   reflow rather than a blank page. */
@font-face {
  font-family: "Newsreader";
  font-style: normal; font-weight: 400; font-display: swap;
  src: url("/static/fonts/newsreader-latin-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Newsreader";
  font-style: normal; font-weight: 500; font-display: swap;
  src: url("/static/fonts/newsreader-latin-500.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Plex Arabic";
  font-style: normal; font-weight: 400; font-display: swap;
  src: url("/static/fonts/plexarabic-arabic-400.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family: "Plex Arabic";
  font-style: normal; font-weight: 600; font-display: swap;
  src: url("/static/fonts/plexarabic-arabic-600.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

:root {
  /* THE BRAND IS NAVY AND YELLOW now -- the poster, the icon and the
     Telegram page all carry it, and the site was the one thing still in
     teal. Neutrals are biased COOL to sit under navy: the old warm paper
     was picked for teal and reads yellowish under this ink. */
  --paper:      #f4f6fb;
  --card:       #ffffff;
  --ink:        #14213d;
  --ink-2:      #4b5670;
  --ink-3:      #7d879c;
  --line:       #dde3ee;
  --line-2:     #ebeff6;
  --accent:     #0b1f4d;
  --accent-ink: #ffffff;
  --accent-bg:  #e7ecf7;
  /* Yellow is spent on exactly the things that ask for money or a step:
     the trial strip, Upgrade, "see the plans". Everywhere else stays quiet
     so those keep their pull. */
  --action:     #f5c400;
  --action-ink: #0b1f4d;
  /* The header on a phone and the sidebar on a desktop: navy, like the
     poster. Controls inside it are white or translucent. */
  --top:        #0b1f4d;
  --top-ink:    #ffffff;
  --top-line:   rgba(255,255,255,.2);
  --top-field:  rgba(255,255,255,.08);
  --fresh:      #17794f;
  --stale:      #9a6a10;
  --bad:        #a8341f;
  /* "You are on the limited plan" — amber, and deliberately not --stale,
     which means a job posting is old. Two different ideas, two colours. */
  --limited:    #c8a23a;
  --radius:     14px;
  --shadow:     0 1px 2px rgba(11, 31, 77, .05),
                0 8px 24px -12px rgba(11, 31, 77, .18);
  /* Plex Arabic sits FIRST so Arabic glyphs are claimed by it; its
     unicode-range means Latin never reaches it and falls through to the
     system stack on the same line. */
  --font: "Plex Arabic", -apple-system, BlinkMacSystemFont, "Segoe UI",
          Roboto, "Helvetica Neue", Tahoma, Arial, sans-serif;
  --serif: "Newsreader", "Plex Arabic", Georgia, "Times New Roman", serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Dark mode is the poster's navy with yellow on it. */
    --paper: #0b1f4d;  --card: #12306f;  --ink: #ffffff;
    --ink-2: #c3cbe0;  --ink-3: #8d98b8; --line: #2a4480;
    --line-2: #1c3a75;
    --accent: #f5c400; --accent-ink: #0b1f4d; --accent-bg: rgba(245,196,0,.16);
    --fresh: #45c98c;  --stale: #d9a63c; --bad: #ff8f79;
    --limited: #d9b455;
    --top: #08183d;
    --shadow: 0 1px 2px rgba(0,0,0,.35), 0 10px 28px -14px rgba(0,0,0,.6);
  }
}
/* The in-app toggle must win over the OS preference in BOTH directions. */
:root[data-theme="dark"] {
  /* Dark mode is the poster's navy with yellow on it. */
  --paper: #0b1f4d;  --card: #12306f;  --ink: #ffffff;
  --ink-2: #c3cbe0;  --ink-3: #8d98b8; --line: #2a4480;
  --line-2: #1c3a75;
  --accent: #f5c400; --accent-ink: #0b1f4d; --accent-bg: rgba(245,196,0,.16);
  --fresh: #45c98c;  --stale: #d9a63c; --bad: #ff8f79;
  --limited: #d9b455;
  --top: #08183d;
  --shadow: 0 1px 2px rgba(0,0,0,.35), 0 10px 28px -14px rgba(0,0,0,.6);
}
:root[data-theme="light"] {
  --paper: #f4f6fb;  --card: #ffffff;  --ink: #14213d;
  --ink-2: #4b5670;  --ink-3: #7d879c; --line: #dde3ee;
  --line-2: #ebeff6; --limited: #c8a23a;
  --accent: #0b1f4d; --accent-ink: #ffffff; --accent-bg: #e7ecf7;
  --fresh: #17794f;  --stale: #9a6a10; --bad: #a8341f;
  --top: #0b1f4d;
  --shadow: 0 1px 2px rgba(11,31,77,.06), 0 8px 24px -12px rgba(11,31,77,.16);
}

* { box-sizing: border-box; }

/*
  The `hidden` attribute must win, always.

  The browser implements `hidden` as `[hidden] { display: none }` in its own
  stylesheet, which loses to ANY class rule that sets display. `.sheet` sets
  display:flex and `.gate` sets display:grid, so both stayed on screen with
  hidden="" set — the settings overlay sat invisibly on top of the whole app,
  swallowing every click, and the "empty" dropdowns were the untouched <select>
  elements straight from the HTML.

  Fixing it per-component would leave the trap armed for the next thing that
  gets a display value, so it is fixed once, here, for everything.
*/
[hidden] { display: none !important; }

html, body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
  overflow-x: hidden;
}

/* The serif, applied where it earns its keep: the things a reader's eye
   lands on first. Body copy, labels and controls stay in the sans — a
   serif at 14px on a phone is a worse read, not a better one. */
h1, h2, h3, .serif {
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -.012em;
  line-height: 1.18;
  text-wrap: balance;
}
h1 { font-size: 2rem; }
h2 { font-size: 1.375rem; }
h3 { font-size: 1.125rem; font-weight: 500; }

/* TEXTAREA WAS MISSING FROM THIS LINE, and that is the whole of the black-CV
   bug. Without `color: inherit` a textarea keeps the browser's own default
   ink -- black -- and #setCv sits on var(--paper), which in dark mode is
   #14120f. Black text on near-black paper: the CV was there and unreadable.
   .build-cv-editor escaped it only because it happens to set its own colour. */
button, input, select, textarea { font: inherit; color: inherit; }

/* EVERY CONTROL IS STYLED BY ELEMENT, NOT BY ITS WRAPPER.
   The rule used to be `.field input`, so a control that happened not to sit
   inside a .field got no styling at all and fell back to the browser's --
   which on Android is a WHITE box whatever the theme says. #cliqPayer, the
   name someone types to be matched to their own bank transfer, was exactly
   that: a white slab in the middle of a dark page, on the one screen where
   the user is being asked to trust us with money.
   Styling by element means the next control added anywhere cannot repeat it.

   APPEARANCE ONLY, DELIBERATELY NO WIDTH. `.quicksearch select` and
   `.chat-bar input` lay themselves out with flex:1 and set no width of their
   own, so a width here would silently reflow the header and the chat bar --
   fixing a colour by breaking two layouts. Width stays with whoever owns the
   layout. */
input:not([type="file"]):not([type="checkbox"]):not([type="radio"]),
select,
textarea {
  padding: 11px 12px;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 10px;
}
/* The one bare control that needs to fill its sheet. */
#cliqPayer, #wayBackEmail, #wayBackPass { width: 100%; box-sizing: border-box; }
/* Two fields, one above the other, the same width. Without this the
   password box was sized to its placeholder and sat narrower than the
   email box above it, which read as a broken form. */
#wayBackEmail { margin-bottom: 8px; }
input:not([type="file"]):focus, select:focus, textarea:focus {
  border-color: var(--accent);
}

/* Placeholders must be READABLE, not invisible. Firefox dims them further on
   its own, so the opacity reset is not decoration. */
::placeholder { color: var(--ink-3); opacity: 1; }

/* Chrome paints autofilled fields with its own near-white background and
   ignores `background`. The inset shadow is the only thing that covers it,
   and text-fill-color is the only thing that recolours the text. The name
   field is autofilled from the phone's contact card, so this is that screen. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ink);
  -webkit-box-shadow: 0 0 0 1000px var(--paper) inset;
  box-shadow: 0 0 0 1000px var(--paper) inset;
  caret-color: var(--ink);
}

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ============================== sign in ============================== */

.gate {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px 18px calc(24px + env(safe-area-inset-bottom));
}
.gate-card {
  width: 100%; max-width: 400px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 26px 22px;
  box-shadow: var(--shadow);
}
.mark { display: inline-flex; gap: 4px; align-items: flex-end; height: 22px; }
.mark-dot {
  width: 6px; border-radius: 3px; background: var(--accent);
  animation: sweep 2.4s ease-in-out infinite;
}
.mark-dot:nth-child(1) { height: 10px; }
.mark-dot:nth-child(2) { height: 18px; animation-delay: .25s; }
.mark-dot:nth-child(3) { height: 13px; animation-delay: .5s; opacity: .55; }
.mark.sm { height: 16px; }
/* THE BRAND IN THE HEADER: the magnifier-with-a-person mark and the word
   فرصك with its yellow ر -- the same drawing as the app icon and the
   poster, so the tab, the home screen and the page agree. */
.brand {
  display: inline-flex; align-items: center; gap: 8px; flex: none;
  color: var(--top-ink); text-decoration: none;
}
.brand svg { width: 22px; height: 22px; display: block; color: var(--action); }
.brand-word {
  font-weight: 700; font-size: 1.25rem; line-height: 1; letter-spacing: -.01em;
  direction: rtl; unicode-bidi: isolate;
}
.brand-word i { font-style: normal; color: var(--action); }
/* The same mark on the sign-in and wall cards, in the accent. */
.gate-mark { width: 44px; height: 44px; display: block; margin: 0 auto 14px; color: var(--accent); }
.mark.sm .mark-dot { width: 4px; }
.mark.sm .mark-dot:nth-child(1) { height: 7px; }
.mark.sm .mark-dot:nth-child(2) { height: 13px; }
.mark.sm .mark-dot:nth-child(3) { height: 9px; }
@keyframes sweep {
  0%, 100% { transform: scaleY(1); }
  50%      { transform: scaleY(1.5); }
}
@media (prefers-reduced-motion: reduce) {
  .mark-dot { animation: none; }
}

.gate-title {
  margin: 12px 0 4px;
  font-size: 1.6rem; font-weight: 650; letter-spacing: -.02em;
  text-wrap: balance;
}
.gate-sub {
  margin: 0 0 20px;
  color: var(--ink-2); font-size: .93rem; text-wrap: pretty;
}

.tabs {
  display: flex; gap: 4px; margin-bottom: 18px;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: 10px; padding: 3px;
}
.tab {
  flex: 1; padding: 8px 10px; border: 0; border-radius: 8px;
  background: transparent; color: var(--ink-2);
  font-size: .88rem; font-weight: 550; cursor: pointer;
}
.tab.is-on { background: var(--card); color: var(--ink); box-shadow: var(--shadow); }

.field { display: block; margin-bottom: 14px; }
.field > span {
  display: block; margin-bottom: 6px;
  font-size: .78rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
.field input, .field select, .field textarea {
  width: 100%; padding: 11px 12px;
  background: var(--paper);
  border: 1px solid var(--line); border-radius: 10px;
}
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--accent);
}
.field .sub {
  display: block; margin-top: 5px;
  font-size: .76rem; color: var(--ink-3); line-height: 1.4;
}
/* The reveal sits INSIDE the box rather than beside it: a control next to
   the field would shorten the field, and this is the one input on the screen
   that most needs its full width. Padding-inline-end keeps the typing clear
   of the button, and it is logical padding so it moves side with the
   language. */
.pw-row { position: relative; display: block; }
.pw-row input { padding-inline-end: 44px; }
.pw-eye {
  position: absolute; inset-inline-end: 4px; top: 50%;
  transform: translateY(-50%);
  width: 36px; height: 36px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: 8px;
  font-size: 17px; line-height: 1; cursor: pointer; opacity: .65;
}
.pw-eye:hover, .pw-eye:focus-visible { opacity: 1; }
.field .sub.is-custom { color: var(--accent); }
.field .sub.is-warn { color: var(--stale); }

.btn {
  width: 100%; padding: 12px 14px; margin-top: 6px;
  border: 1px solid var(--line); border-radius: 11px;
  background: var(--card); color: var(--ink);
  font-weight: 600; cursor: pointer;
}
.btn-primary {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
}
.btn-primary[disabled] { opacity: .6; cursor: progress; }
.btn-quiet { background: transparent; border-color: transparent; color: var(--ink-3); }

/* The owner's switch. Deliberately NOT the accent colour: it must not read
   as the encouraged action on a billing page, and it must not look like a
   purchase button in a screenshot. Dashed, muted, obviously a tool. */
.btn-owner {
  margin-top: 10px;
  background: transparent;
  border: 1px dashed var(--line);
  color: var(--ink-3);
  font-size: 14px;
}
.btn-owner:hover:not(:disabled) { color: var(--ink); }
.lang {
  display: block; margin: 14px auto 0; padding: 6px 10px;
  background: none; border: 0; color: var(--ink-3);
  font-size: .85rem; text-decoration: underline; cursor: pointer;
}
.err {
  margin: 0 0 12px; padding: 9px 11px;
  background: color-mix(in srgb, var(--bad) 12%, transparent);
  border-inline-start: 3px solid var(--bad); border-radius: 6px;
  color: var(--bad); font-size: .87rem;
}

/* =============================== header =============================== */

.top {
  position: sticky; top: 0; z-index: 20;
  background: var(--top);
  color: var(--top-ink);
  padding: calc(10px + env(safe-area-inset-top)) 0 8px;
}
.top-row {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 12px; padding: 0 16px 10px;
  max-width: 680px; margin: 0 auto;
}
.top-row > .mark { flex: none; }
/* THE ROW HOLDS FOUR THINGS AND A PHONE IS 390px WIDE.
   Squeezing them onto one line meant the country and job were elided down
   to "Jordan - Mechan..." -- which is the one line in the header a person
   is actually reading. So the row wraps instead: the mark and the account
   controls keep the top line, and the country, job and pool count drop to a
   full-width line under them where nothing has to be cut.

   The ellipsis below stays as a floor, for a country and profession longer
   than any we ship. It is no longer what normally happens. */
.top-id {
  display: flex; flex-direction: column; justify-content: center;
  flex: 1 1 auto; min-width: 0;
}
.market {
  font-size: .95rem; font-weight: 650; letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.poolline {
  font-size: .76rem; color: color-mix(in srgb, var(--top-ink) 62%, transparent);
  font-variant-numeric: tabular-nums;
  /* Same treatment: "60 live - last collected 6 days ago" is longer than the
     title above it and was the line actually forcing the row open. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.poolline.is-bad { color: #ffb4a3; }
.top-actions { display: flex; align-items: center; gap: 8px; flex: none; }

/* Below this width the mark and the account controls take the top line by
   themselves, and the country-and-job line follows underneath at the full
   width of the screen. The plan control keeps every part of itself -- it is
   no longer competing with anything. */
@media (max-width: 560px) {
  .top-id { flex: 1 0 100%; order: 3; }
  .top-actions { margin-inline-start: auto; }
  .top-row { gap: 10px; }
}
/*
  THE PLAN CONTROL.

  It used to be a 20px pill of accent text on an accent tint: the lowest
  contrast pair in the palette, no border, no verb, and far under a 44px
  touch target. Every one of those says "label", so it was read once and
  never pressed — which is a problem when it is the only route to the thing
  that pays for the product.

  Now it is a two-part control. Left: a state dot and the plan name. Right:
  a filled pill carrying a VERB. The whole thing is one target.
*/
.plan {
  display: inline-flex; align-items: center; gap: 10px;
  height: 38px; padding: 0 4px 0 13px;
  background: var(--top-field); border: 1px solid var(--top-line);
  border-radius: 99px;
  font-size: .84rem; font-weight: 500; color: var(--top-ink);
  white-space: nowrap;
}
.plan-state { display: inline-flex; align-items: center; gap: 7px; }
.plan-dot {
  width: 7px; height: 7px; border-radius: 99px;
  background: var(--action);
}
.plan-go {
  display: inline-flex; align-items: center; gap: 5px;
  height: 30px; padding: 0 12px;
  background: var(--action); color: var(--action-ink);
  border-radius: 99px; font-size: .81rem; font-weight: 600;
}
.plan-go svg { display: block; }

/* Paid: the dot goes green and the call to action disappears entirely.
   Nobody holding a live subscription should still be told to upgrade. */
.plan.is-paid {
  padding-inline-end: 13px;
}
.plan.is-paid .plan-dot { background: var(--fresh); }
.plan.is-paid .plan-go { display: none; }

/* On a phone the control is the touch target, so it gets the full 44. */
@media (max-width: 560px) {
  .plan { height: 44px; padding-inline-start: 14px; }
  .plan-go { height: 34px; }
}
.icon {
  width: 34px; height: 34px; display: grid; place-items: center;
  background: var(--top-field); border: 1px solid var(--top-line);
  color: var(--top-ink);
  border-radius: 9px; cursor: pointer;
}

/* WHOSE SESSION THIS IS, ON A BUTTON.
   Round where .icon is square, because it stands for a person and not for an
   action. It carries the first letter of the address rather than a generic
   figure -- on a shared phone that letter is the whole answer, and it is
   there before the page is opened. */
/* The language switch in the header: a small pill naming the language
   it switches to, sized like the avatar beside it. */
.lang-pill {
  height: 34px; flex: none; padding: 0 11px;
  background: var(--top-field); color: var(--top-ink);
  border: 1px solid var(--top-line); border-radius: 999px;
  font: inherit; font-size: .78rem; font-weight: 700; line-height: 1;
  cursor: pointer;
}
.lang-pill:hover { border-color: var(--action); color: var(--action); }

.avatar {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  background: var(--top-field); color: var(--top-ink);
  border: 1px solid var(--top-line); border-radius: 50%;
  font-weight: 700; font-size: .9rem; line-height: 1;
  cursor: pointer; padding: 0;
  /* An email is Latin even in an Arabic interface, so its initial must not
     be mirrored into the wrong corner of a round button. */
  direction: ltr;
}
.avatar.lg {
  width: 52px; height: 52px; font-size: 1.35rem; cursor: default;
}

/* The identity line at the top of the account page: who, and whether the
   address has been confirmed. */
.idcard {
  display: flex; align-items: center; gap: 12px;
  padding: 4px 0 14px;
}
.idcard-who { min-width: 0; display: grid; gap: 2px; }
.idcard-who strong {
  font-size: 1rem; font-weight: 650; word-break: break-all;
}
.idcard-who .sub { font-size: .78rem; color: var(--ink-3); }
.idcard-who .sub.is-bad { color: var(--bad); }

/* The facts. A two-column grid rather than a table: the labels are short and
   the values are not, and on a narrow phone a table would either scroll
   sideways or squeeze the value into a column two words wide. */
.facts {
  display: grid; grid-template-columns: auto 1fr;
  gap: 8px 16px; margin: 0 0 18px;
  border-top: 1px solid var(--line-2); padding-top: 14px;
}
.facts dt {
  font-size: .78rem; color: var(--ink-3); line-height: 1.5;
  align-self: start;
}
.facts dd {
  margin: 0; font-size: .9rem; line-height: 1.5;
  min-width: 0; overflow-wrap: anywhere;
}

/* THE ACCOUNT PAGE IS THREE THINGS, NOT ONE LIST.
   It grew by absorbing the settings sheet, and everything landed in one
   undifferentiated stack: your email, then the jobs you follow, then roles,
   then alerts, then Save, then sign out -- with nothing saying where one
   subject ended and the next began. A pane per subject, with its own
   heading, is the whole fix. */
.pane {
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px 14px 16px;
  margin: 0 0 14px;
  background: var(--card);
  display: flex; flex-direction: column; gap: 12px;
}
.pane-title {
  margin: 0;
  font-size: .82rem; font-weight: 650;
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-3);
}
/* The panes carry the spacing now, so the fields inside them do not need
   their own bottom margins fighting the gap. */
.pane .field { margin: 0; }

/* WHO IS SIGNED IN, and on what plan. The two questions this page is opened
   to answer, so they share the top of it and neither is buried in a list. */
#profile .idcard {
  display: flex; align-items: center; gap: 12px;
  padding: 4px 2px 16px;
}
#profile .idcard-who { flex: 1; min-width: 0; }
#profile .idcard-who strong {
  display: block; font-size: 1.02rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.planpill {
  flex: none;
  padding: 5px 12px; border-radius: 999px;
  border: 1px solid var(--line);
  font-size: .78rem; font-weight: 650;
  letter-spacing: .02em;
  color: var(--ink-3);
  white-space: nowrap;
}
.planpill.is-paid {
  background: var(--accent-bg);
  border-color: transparent;
  color: var(--accent);
}

/* A LABEL ABOVE ITS CONTROL, not floating beside it. Each field is one
   question, and the question reads before the answer. */
.field-label {
  display: block;
  font-size: .84rem; font-weight: 600;
  margin-bottom: 2px;
}

/* The job picker and its button on one line: choosing a job and adding it
   are one action, and stacking them made two. Wraps on a narrow phone
   rather than squeezing the select down to nothing. */
.picker-row {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.picker-row select { flex: 1 1 12rem; min-width: 0; }
.picker-row .btn { flex: none; }

/* A pane's own actions sit at its end, separated by a hairline, so it is
   obvious which section a Save belongs to. That was the confusion worth
   fixing: one Save at the bottom of a long page looks like it saves the
   page, and this one only ever saved the jobs and roles above it. */
.pane-foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
/* THESE ARE BUTTONS, so they look like buttons. btn-quiet is borderless by
   design -- right beside a solid one, wrong on its own in a row, where
   "Plan and payment" and "العربية" read as two lines of centred text with
   nothing to press. */
.pane-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.pane-actions .btn {
  flex: 1 1 auto;
  border: 1px solid var(--line);
  background: var(--paper);
}
.pane-actions .btn:hover { border-color: var(--accent); }
#profile .pane-foot .btn-quiet {
  border: 1px solid var(--line);
  background: var(--paper);
}

/* SIGNING OUT IS NOT AN ORDINARY ACTION. It is the one button here nobody
   wants to press by accident, so it is set apart from the two beside it and
   coloured as what it is -- without shouting, because it is also perfectly
   normal to want it. */
.btn-danger-quiet {
  width: 100%;
  margin-top: 4px;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--bad);
}
.btn-danger-quiet:hover { border-color: var(--bad); }

/* On a phone the page is the whole screen, so the panes lose their side
   borders and become bands -- less boxing-in, and the headings still do the
   separating. */
/* ROOM AT THE BOTTOM. The last section ran under the page footer -- Sign
   out was reachable only by scrolling past something that looked like the
   end of the page. */
/* Room to scroll past the last button, without the empty screen that 96px
   left behind. */
#profile .sheet-card { padding-bottom: 32px; }

@media (max-width: 520px) {
  #profile .pane {
    border-inline: 0; border-radius: 0;
    margin-inline: -14px;
    padding-inline: 14px;
  }
}

/* THE CLOSING ASSESSMENT IS NOT ANOTHER QUESTION.
   It is the part of a mock interview worth keeping -- an honest verdict, the
   answer that worked, and a written-out better version of the one that did
   not -- so it does not arrive looking like the fifth grey bubble in a row. */
.bubble.is-verdict {
  border-inline-start: 3px solid var(--accent);
  background: var(--accent-bg);
}

/* THE REPORT IS A DOCUMENT, NOT A REMARK.
   A score, what worked, what did not, and a model answer for every question
   -- the part somebody keeps and rereads before the real interview. At chat
   width and chat spacing it read as one enormous message; it needs the width
   of the page and air between its sections. */
.bubble.is-report {
  max-width: 100%;
  white-space: pre-wrap;
  line-height: 1.62;
  padding: 16px 18px;
}
/* The model answers are the reason this exists. They are the longest thing
   in it, so the eye needs the headings to find them again. */
.bubble.is-report strong { display: inline-block; margin-top: 4px; }

/* Once the interview is over the composer stays usable -- people say thank
   you, or ask one last thing -- but it stops inviting an answer, because
   there is no longer a question waiting for one. */
.chat.is-done .chat-bar { opacity: .72; }
.chat.is-done #interviewHint { color: var(--accent); font-weight: 600; }

/* Country + job, always visible — no settings sheet needed to change either. */
.quicksearch {
  display: flex; gap: 8px;
  padding: 0 16px 8px; max-width: 680px; margin: 0 auto;
}
.quicksearch select {
  flex: 1; min-width: 0; padding: 8px 10px;
  background: #ffffff; color: #0b1f4d;
  border: 1px solid transparent; border-radius: 10px;
  font-size: .86rem; font-weight: 600;
}
.quicksearch select:focus { border-color: var(--action); outline: none; }

.filters {
  display: flex; gap: 6px; overflow-x: auto;
  padding: 0 16px 2px; max-width: 680px; margin: 0 auto;
  scrollbar-width: none;
}
.filters::-webkit-scrollbar { display: none; }
.filters.secondary { margin-top: 6px; }
.chip {
  flex: none; padding: 6px 12px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: 99px; color: var(--ink-2);
  font-size: .82rem; font-weight: 550; white-space: nowrap; cursor: pointer;
}
/* CHOSEN LOOKS LIKE CHOSEN, EVERYWHERE.
   There were two different greens on the account page, one above the other:
   a followed job drawn as a tinted pill, a selected role as a SOLID accent
   slab. Both mean the same thing to a reader -- "this one is on" -- so two
   paints for it read as two kinds of thing and the rows looked half-broken.
   Tinted wins for both: legible on either theme, it does not shout over a
   whole row, and the remove x on a job chip is readable on it, which it was
   not on solid accent at this size. */
.chip.is-on,
.chip-removable.is-on {
  background: var(--accent-bg);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

/* The feed's own filter strip keeps the solid fill. It scrolls alone with
   nothing to be consistent WITH, and the stronger paint is what makes the
   active filter findable there. */
.filters .chip.is-on {
  background: var(--accent); border-color: var(--accent);
  color: var(--accent-ink);
}
/* Chips that live in the navy header: translucent white, and the chosen
   one goes yellow. */
.top .chip {
  background: var(--top-field); border-color: var(--top-line); color: var(--top-ink);
}
.top .filters .chip.is-on, .top .chip-go {
  background: var(--action); border-color: var(--action); color: var(--action-ink);
}
.top .act-cv  { background: rgba(255,255,255,.14); border-inline-start-color: var(--action); }
.top .act-best { border-inline-start-color: rgba(255,255,255,.55); }
.top .act-ask  { border-inline-start-color: rgba(255,255,255,.35); }
.top .act:hover { border-color: var(--top-line); }
.top .act-cv:hover   { border-inline-start-color: var(--action); }
.top .act-best:hover { border-inline-start-color: rgba(255,255,255,.55); }
.top .act-ask:hover  { border-inline-start-color: rgba(255,255,255,.35); }

/* THE THREE ACTIONS, TOLD APART.
   They sat in a row as identical grey pills, so the only way to know which
   was which was to read all three every time. They are not variations of one
   action either: one writes you a document, one reads the feed for you, one
   opens a conversation. Each gets a mark and its own weight.
   The colour is carried on the LEFT EDGE and the icon rather than by
   flooding the pill, so three of them side by side still read as one row of
   controls instead of a traffic light. */
.act {
  display: inline-flex; align-items: center; gap: 6px;
  padding-inline-start: 10px;
  border-inline-start-width: 3px;
  color: var(--ink);
}
.act-ico { font-size: .95em; line-height: 1; }
/* Build my CV leads: it is the one that leaves you holding something. */
.act-cv {
  border-inline-start-color: var(--accent);
  background: var(--accent-bg);
  font-weight: 650;
}
.act-best { border-inline-start-color: var(--limited); }
.act-ask  { border-inline-start-color: var(--ink-3); }
.act:hover { border-color: var(--line); }
.act-cv:hover   { border-inline-start-color: var(--accent); }
.act-best:hover { border-inline-start-color: var(--limited); }
.act-ask:hover  { border-inline-start-color: var(--ink-3); }
/* The one action on this screen that DOES something to the world, rather
   than just re-filtering what is already here. It reads as a button. */
.chip-go {
  background: var(--accent); border-color: var(--accent);
  color: var(--accent-ink); font-weight: 650;
}
.chip-go[disabled] { opacity: .65; cursor: progress; }
.chip-go .spin {
  display: inline-block; width: 9px; height: 9px; margin-inline-end: 5px;
  border: 2px solid currentColor; border-top-color: transparent;
  border-radius: 50%; vertical-align: -1px;
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .chip-go .spin { animation: none; } }

.empty .btn {
  max-width: 260px; margin: 16px auto 0;
}

/* ============================ notice / feed ============================ */

/* A NOTICE IS A CARD, NOT A GREEN SLAB.
   Filled accent, an accent border and an accent heading, all at once, on a
   panel that is on screen every time a free user opens the app: it shouted
   without saying anything, and the green fought the same accent doing real
   work on the buttons. It is a card like the vacancies are cards now -- the
   colour left in it is one amber dot, matching the plan control it is
   telling you about. */
.notice {
  max-width: 680px; margin: 12px auto 0; padding: 13px 15px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  font-size: .85rem; line-height: 1.5; color: var(--ink-2);
}
.notice strong {
  display: block; margin-bottom: 3px;
  color: var(--ink); font-weight: 600;
}
#upsell strong::before {
  content: ""; display: inline-block;
  width: 7px; height: 7px; border-radius: 99px;
  background: var(--limited);
  margin-inline-end: 8px; vertical-align: middle;
}

/* ------------------------------- toast -------------------------------- */
/* One line, at the top, over whatever is there. This replaces alert(): a
   blocking dialog that Android labels "forasak.com says", so the app's own
   errors arrived looking like a browser warning about a website. It is also
   the one surface that must be readable in both themes on a first paint, so
   it is built from the same tokens as everything else. */
.toast {
  position: fixed; inset-inline: 12px; top: 12px; z-index: 60;
  max-width: 560px; margin-inline: auto;
  padding: 12px 15px;
  background: var(--card);
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  color: var(--ink);
  font-size: .88rem; line-height: 1.5;
  cursor: pointer;
}
.toast[hidden] { display: none; }
.toast-bad { border-inline-start-color: var(--stale); }

/* ------------------------------ billing ------------------------------ */
/* The plan badge is the way in, so it has to look pressable. */
.plan { cursor: pointer; }
.plan:hover { border-color: var(--accent); }
.plan:hover .plan-go { background: color-mix(in srgb, var(--accent) 88%, #000); }

.billnow {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 16px;
}
.billnow-row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; padding: 4px 0;
}
.billnow-row span { color: var(--ink-3); font-size: .82rem; }
.billnow-row strong { font-size: .92rem; }

.plans { display: flex; flex-direction: column; gap: 12px; }
.plancard {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px;
}
.plancard.is-current { border-color: var(--accent); }
.plancard-top {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 10px; margin-bottom: 6px;
}
.plancard-name { font-weight: 650; }
.plancard-price { font-variant-numeric: tabular-nums; white-space: nowrap; }
.plancard-price small { color: var(--ink-3); font-weight: 400; }
.plancard-blurb { color: var(--ink-2); font-size: .84rem; margin: 0 0 8px; }
.plancard ul { margin: 0; padding-inline-start: 18px; }
.plancard li { font-size: .82rem; color: var(--ink-2); padding: 2px 0; }
.plancard .tag {
  font-size: .68rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--accent); border: 1px solid var(--accent);
  border-radius: 999px; padding: 1px 7px;
}

.billsub { font-size: .84rem; margin: 20px 0 6px; }
.billhist { list-style: none; margin: 0; padding: 0; }
.billhist li {
  display: flex; justify-content: space-between; gap: 10px;
  font-size: .76rem; color: var(--ink-3);
  padding: 5px 0; border-bottom: 1px solid var(--line);
}
.billhist li:last-child { border-bottom: 0; }

/* Verification is a blocker, not an accent-coloured suggestion. */
.notice.warn {
  background: color-mix(in srgb, var(--stale) 12%, transparent);
  border-color: color-mix(in srgb, var(--stale) 45%, transparent);
}
.notice.warn strong { color: var(--stale); }
.notice.warn .btn { max-width: 220px; margin-top: 10px; }
.devlink {
  margin: 8px 0 0; font-size: .72rem; color: var(--ink-3);
  word-break: break-all;
}
.feed {
  max-width: 680px; margin: 0 auto;
  padding: 12px 16px calc(28px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; gap: 10px;
}

.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 13px 15px;
  box-shadow: var(--shadow);
}
.card-top {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 8px; flex-wrap: wrap;
}
.src {
  font-size: .74rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}
.age {
  margin-inline-start: auto;
  font-size: .76rem; font-variant-numeric: tabular-nums; color: var(--ink-3);
}
.dot-fresh, .dot-stale {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
}
.dot-fresh { background: var(--fresh); }
.dot-stale { background: var(--stale); }

.card-text {
  margin: 0; font-size: .93rem; line-height: 1.55;
  white-space: pre-wrap; word-break: break-word;
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical;
  overflow: hidden;
}
.card.is-open .card-text { -webkit-line-clamp: unset; }
.more {
  margin-top: 4px; padding: 0; background: none; border: 0;
  color: var(--accent); font-size: .82rem; font-weight: 600; cursor: pointer;
}

.tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 9px; }
.tag {
  padding: 2px 8px; border-radius: 6px;
  background: var(--accent-bg); color: var(--accent);
  font-size: .74rem; font-weight: 600;
}
.tag.muted { background: var(--paper); color: var(--ink-3); }
/* A role the JOB SITE matched to our search term, not one we found in the
   post. Kept because dropping them loses real vacancies, but drawn as
   provisional — dashed, with a "?" — so it never reads as our own judgement. */
.tag.is-guess {
  border: 1px dashed var(--line);
  padding: 1px 7px;
  font-style: italic;
  cursor: help;
}

/* A link, a number or an address inside the post text. Underlined so it
   reads as pressable; LTR so an address does not get flipped inside an
   Arabic sentence. */
.card-text a.inlink { color: var(--accent); text-decoration: underline;
  text-underline-offset: 2px; word-break: break-all; direction: ltr;
  unicode-bidi: embed; }

.card-foot {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 11px; padding-top: 10px; border-top: 1px solid var(--line);
}
.open {
  display: inline-block; padding: 4px 11px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card);
  color: var(--accent); font-size: .86rem; font-weight: 650;
  text-decoration: none;
}
.open:hover { text-decoration: none; border-color: var(--accent); }
/* The apply buttons and Share carry their own paint; the neutral outline
   above is only for "Open post". */
.card-foot .open[class*="ap-"]:not(.ap-share) { border-color: transparent; }
/* A way to apply read off the post: a number, an address, a form. These are
   the card's real buttons now, so they look like buttons -- and a phone
   number is set LTR whatever the page direction, or "0786070746" renders
   backwards in Arabic. */
.ap-call, .ap-mail, .ap-wa, .ap-link {
  display: inline-block; padding: 5px 11px; border-radius: 999px;
  background: var(--accent); color: var(--paper, #fff);
  font-size: .82rem; direction: ltr; unicode-bidi: isolate;
}
.ap-call:hover, .ap-mail:hover, .ap-wa:hover, .ap-link:hover {
  text-decoration: none; filter: brightness(1.08);
}
.ap-wa { background: #25d366; color: #fff; }
/* Share sits with the apply buttons but is not one of them: outlined, so
   the eye still lands on Call / WhatsApp / Apply first. */
.ap-share {
  display: inline-block; padding: 4px 11px; border-radius: 999px;
  background: transparent; color: var(--accent);
  border: 1px solid var(--accent); font: inherit; font-size: .82rem;
  cursor: pointer;
}
.ap-share:hover { background: var(--accent); color: var(--paper, #fff); }
/* Our own share sheet (desktop, and any browser without a good native
   one): a short list of where the job can go, and the message as it
   will arrive, so nobody is surprised by what they sent. */
.share-card { max-width: 440px; }
.share-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.share-opt {
  display: block; padding: 11px 14px; text-align: center;
  background: var(--card); border: 1px solid var(--line); border-radius: 10px;
  color: var(--ink); font: inherit; font-size: .9rem; font-weight: 600;
  text-decoration: none; cursor: pointer;
}
.share-opt:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.share-preview {
  margin: 14px 0 0; padding: 12px 14px; max-height: 200px; overflow: auto;
  background: var(--paper); border: 1px solid var(--line-2); border-radius: 10px;
  font: inherit; font-size: .84rem; line-height: 1.5; color: var(--ink-2);
  white-space: pre-wrap; word-break: break-word;
}
/* Where the vacancy came from, beneath it. Quiet — it is there to be checked
   when something looks wrong, not to compete with the job itself. */
.foundon { font-size: .78rem; color: var(--ink-3); }
.contact { font-size: .78rem; color: var(--ink-3); margin-inline-start: auto; }

.empty {
  max-width: 680px; margin: 0 auto; padding: 44px 24px;
  text-align: center; color: var(--ink-2); font-size: .92rem;
}
.empty h3 {
  margin: 0 0 6px; font-size: 1.05rem; font-weight: 650; color: var(--ink);
}
.empty .why {
  margin-top: 10px; font-size: .82rem; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.foot {
  max-width: 680px; margin: 0 auto;
  padding: 0 16px calc(30px + env(safe-area-inset-bottom));
  color: var(--ink-3); font-size: .76rem; text-align: center;
}

/* ============================== settings ============================== */

.sheet {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(8, 14, 12, .5);
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet-card {
  width: 100%; max-width: 480px;
  max-height: 88dvh; overflow-y: auto;
  background: var(--card);
  border-radius: 18px 18px 0 0;
  padding: 20px 20px calc(24px + env(safe-area-inset-bottom));
}
@media (min-width: 560px) {
  .sheet { align-items: center; }
  .sheet-card { border-radius: 18px; }
}
.sheet-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 16px;
}
.sheet-head h2 { margin: 0; font-size: 1.15rem; font-weight: 650; }

.builder-card { max-width: 560px; }
.builder-progress {
  color: var(--accent); font-size: .78rem; font-weight: 650;
  margin-bottom: 10px;
}
.builder-question {
  display: block; color: var(--ink); font-size: 1rem;
  font-weight: 650; line-height: 1.45; margin-bottom: 5px;
}
.builder-question-row, .builder-answer-row {
  display: flex; align-items: flex-start; gap: 8px;
}
.builder-question-row .builder-question { flex: 1; }
.builder-answer-row textarea { flex: 1; min-width: 0; }
.builder-help { white-space: pre-line; margin-bottom: 10px; }
.builder-actions { display: grid; grid-template-columns: 1fr 1fr 1.4fr; gap: 8px; }
.builder-actions .btn { margin-top: 0; }
@media (max-width: 380px) {
  .builder-actions { grid-template-columns: 1fr 1fr; }
  #btnBuilderNext { grid-column: 1 / -1; }
}

/* The chips sit directly above the dropdown that adds more of them, and with
   no gap the selected "Quality Control / QC" chip touched the select below
   it -- they read as one broken control rather than as a list and its add
   box. Empty gets no margin, or an unused rolebox leaves a hole. */
.rolebox { display: flex; flex-wrap: wrap; gap: 6px; }
.rolebox:not(:empty) { margin-bottom: 10px; }

/* A chip for something the user CHOSE, with its own remove button. The × is a
   real <button> rather than a styled span so it is reachable by keyboard and
   announces itself; the chip around it is not clickable, so there is no
   nested-control ambiguity about what a tap does. */
.chip-removable {
  display: inline-flex; align-items: center; gap: 6px;
  cursor: default;
}
.chip-x {
  border: 0; background: transparent; color: inherit;
  font-size: 1rem; line-height: 1; padding: 0 1px;
  cursor: pointer; opacity: .7;
}
.chip-x:hover, .chip-x:focus-visible { opacity: 1; }

/* A FOLLOWED JOB IS NOT A SELECTED ROLE, so it must not be drawn as one.
   Both rows used `.chip.is-on` -- solid accent -- one directly above the
   other. But the green pill is a job the account FOLLOWS (a thing that
   exists, removable with its ×), and the grey pills below are roles that are
   OFF and waiting to be tapped. Same paint, two meanings, and the pair read
   as one broken control where half the items had lost their colour.

   The job keeps the accent, quietly: a tinted ground and accent text rather
   than a filled slab. It still reads as chosen, it no longer competes with
   the roles, and the × is legible on it -- which it was not on solid accent
   at this size. */
/* A status that needs attention, and only then. Cancelled-with-time-left is
   NOT one of those: it is a working account, and colouring it as a problem
   was the whole complaint. Reserved for a failed payment or a subscription
   that has actually run out. */
#billStatus.is-warn { color: var(--bad); }

/* (a followed job shares the .chip.is-on paint above) */
.btn-small {
  padding: 6px 12px; font-size: .85rem; align-self: flex-start;
  margin-top: 6px;
}
.hint { color: var(--ink-3); font-size: .8rem; margin: 4px 0 14px; }

.skel {
  height: 96px; border-radius: var(--radius);
  background: linear-gradient(90deg, var(--card) 0%, var(--paper) 50%,
                              var(--card) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.3s linear infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) {
  .skel { animation: none; }
}

/* ============================== the assistant ==============================
   The model's answers used to land above the feed, in the same notice slot
   the verification bar uses. That was right for one sentence and wrong for
   everything the assistant actually produces: a cover letter is 350 words
   and a set of interview questions is longer, and both were poured into a
   bordered strip with the job list underneath, so the reader scrolled their
   own vacancies to finish reading a document written for them.
   It is a page now (.chat, above), the same shape as the CV workspace and
   the conversation. Only the text inside it is styled here. */
.coach-out {
  white-space: pre-wrap;
  word-break: break-word;
  font: inherit;
  margin: 0 auto;
  padding: 18px;
  max-width: 680px; width: 100%;
  line-height: 1.65;
  color: var(--ink);
  overflow-y: auto;
  /* min-height:0 or a flex child grows instead of scrolling, and a long
     letter pushes the close button off the top of the screen. */
  flex: 1; min-height: 0;
}
.coach-row { margin: 0 0 14px; display: flex; flex-direction: column; gap: 3px; }
.coach-row a { color: var(--accent); font-weight: 600; text-decoration: none; }
.coach-why { color: var(--ink-2); font-size: 13px; }
.build-cv-editor {
  width: 100%; min-height: 330px; margin: 10px 0;
  padding: 14px; resize: vertical; line-height: 1.55;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--line); border-radius: 12px;
  font: inherit;
}
.build-cv-editor:focus { border-color: var(--accent); outline: none; }
.build-cv #builtCvHint { display: block; min-height: 1.4em; margin-top: 8px; }

/* Per-card actions. Quiet by default: they are useful, not the point of the
   card, and the link to the vacancy itself must stay the loudest thing. */
.card-ai { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.chip-ai {
  font-size: 12px;
  padding: 5px 11px;
  border-style: dashed;
}
#setCv { width: 100%; resize: vertical; font: inherit; }

/* ================================= chat =================================
   A conversation, not a form. It sits above the feed so an answer about a
   vacancy can be read with the vacancies still on screen. */
/*
  THE ASSISTANT, AS A PAGE.

  It used to be a 46vh panel above the job feed. That shape was the problem:
  a long answer had nowhere to go, the feed showing underneath competed for
  the same eye, and the first thing anybody saw was an empty box with a
  cursor in it. A conversation needs a column of its own.
*/
.chat {
  position: fixed; inset: 0; z-index: 40;
  display: flex; flex-direction: column;
  background: var(--paper);
  /* The assistant scrolls inside .chat-log and never reaches this. The CV
     workspace has no log -- it is a page of controls taller than a phone --
     so without this its Save and Download buttons were simply unreachable. */
  overflow-y: auto;
}

/* Anything in a .chat that is not head, log or composer is ordinary page
   content: give it the same column the log gets instead of letting it run
   edge to edge across a phone. */
.chat > :not(.chat-head):not(.chat-log):not(.chat-bar):not(.chat-empty) {
  max-width: 680px; width: 100%; margin-inline: auto;
  padding-inline: 18px;
}
.chat > .build-cv-editor { width: calc(100% - 36px); }
/* FLEX, NOT A THREE-COLUMN GRID. The grid assumed every head began with a
   back button, so the panels that open straight onto a title -- Build my CV,
   the CV draft -- dropped their title into the 40px slot and wrapped it into
   a three-line stack. A head has a title and some number of buttons; that is
   what this now says. */
.chat-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: calc(10px + env(safe-area-inset-top)) 14px 10px;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(12px);
}
/* ONE LINE, WHATEVER IS IN IT.

   These titles carry a JOB NAME on a good day and, on a Facebook post, the
   first 150 characters of the post itself -- hashtags, emoji, a bare URL.
   With only min-width:0 the header did what it was asked and wrapped: an
   Arabic post title came out one word per line, a header twenty lines tall
   that pushed the conversation off the screen on a phone.

   min-width:0 alone was never enough. A long URL has no break opportunity,
   so it needs overflow-wrap to be breakable at all; and once breakable it
   needs the clamp to stay one line. Both, or the header grows again the
   next time a post arrives with a link in it. */
.chat-head strong {
  flex: 1;              /* takes the room, so the buttons sit at the edges */
  min-width: 0;
  font-size: .95rem; font-weight: 550;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow-wrap: anywhere;
}
.chat-head .icon { flex: none; }

/* The opening screen. Serif, because this is the one moment the page is
   allowed to be a page rather than a tool. */
.chat-empty {
  flex: none;
  max-width: 680px; width: 100%; margin: 0 auto;
  padding: 44px 18px 10px;
}
.chat-greeting {
  margin: 0 0 8px;
  font-size: clamp(1.7rem, 6vw, 2.25rem);
}
.chat-greeting-sub {
  margin: 0 0 26px;
  font-size: 1rem; color: var(--ink-2); max-width: 46ch;
  text-wrap: pretty;
}
.chat-openers {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
@media (max-width: 520px) {
  .chat-openers { grid-template-columns: minmax(0, 1fr); }
}
.opener {
  display: flex; flex-direction: column; gap: 4px;
  align-items: flex-start; text-align: start;
  min-height: 72px; padding: 14px 15px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: 13px; cursor: pointer;
}
.opener:hover { border-color: var(--accent); }
.opener-title { font-size: .92rem; font-weight: 550; }
.opener-sub { font-size: .84rem; color: var(--ink-3); line-height: 1.45; }

.chat-log {
  flex: 1;
  min-height: 0;        /* or a flex child refuses to scroll and grows instead */
  overflow-y: auto;
  max-width: 680px; width: 100%; margin: 0 auto;
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.bubble {
  max-width: 84%;
  padding: 9px 12px;
  border-radius: 14px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
}
/* Sent messages hug the side the reader writes from, which flips with the
   language — so this is margin-inline, not margin-left. */
.bubble.from-me {
  margin-inline-start: auto;
  background: var(--accent);
  color: var(--accent-ink);
  border-end-end-radius: 4px;
}
/* THIS BUBBLE WAS WHITE TEXT ON A WHITE BOX, and had been since it was
   written. It read `background: var(--sunk, #f1f4f5)` and --sunk IS DEFINED
   NOWHERE IN THIS FILE, so the fallback was not a fallback -- it was the
   value, always, a hardcoded near-white. It set no `color` either, so the
   text inherited --ink, which in the dark theme is #f2ece3. The user's
   generated CV was rendered invisible on the screen where they read it.
   A var() fallback for a token that does not exist looks theme-aware in
   review and cannot be. Both halves are named tokens now. */
.bubble.from-ai {
  margin-inline-end: auto;
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-end-start-radius: 4px;
}
.bubble.is-waiting { opacity: .6; font-style: italic; }
.voice-control {
  flex: 0 0 auto;
  width: 42px; min-height: 42px; padding: 0;
  border: 1px solid var(--line, #dfe4e6); border-radius: 10px;
  background: var(--paper, #f7f8f8); color: var(--ink, #172126);
  font-size: 18px; line-height: 1; cursor: pointer;
}
.voice-control:hover, .voice-control:focus-visible {
  border-color: var(--accent, #0b1f4d); outline: none;
}
.voice-control.is-active {
  background: var(--accent, #0b1f4d); color: #fff;
  border-color: var(--accent, #0b1f4d);
}
.bubble .voice-control {
  display: block; width: 34px; min-height: 30px;
  margin-top: 7px; font-size: 15px;
}
/* The line explaining what in a generated CV was written and what was carried
   over. It is a caption, not a turn in the conversation, so it does not get a
   bubble's background. */
.bubble.is-note {
  background: none;
  padding: 2px 2px 0;
  max-width: 100%;
  font-size: 13px;
  color: var(--ink-2);
}
.chat .coach-actions {
  margin: 0;
  padding: 0 12px 10px;
  border-top: 1px solid var(--line, #dfe4e6);
  padding-top: 10px;
}
/* An error the assistant returned. Tokens, for the same reason as .from-ai:
   a fixed pale-pink ground stays pale in the dark theme, and then it is the
   one bubble on the screen that glows. */
.bubble.is-bad {
  background: color-mix(in srgb, var(--bad) 12%, var(--card));
  color: var(--bad);
  border: 1px solid color-mix(in srgb, var(--bad) 35%, var(--card));
}
.chat-bar {
  flex: none;
  display: flex;
  align-items: stretch;
  gap: 8px;
  max-width: 680px; width: 100%; margin: 0 auto;
  padding: 10px 18px calc(14px + env(safe-area-inset-bottom));
}
/* The composer floats on the paper rather than sitting in a bordered strip:
   with the log scrolling behind it, a full-width rule reads as the end of
   the page instead of the edge of an input. */
.chat-bar > * { align-self: center; }
/* ONE LINE HAS TO FIT, AND IT DID NOT.
   min-height was 46px. Take away 12px of padding top and bottom and 1px of
   border each side and 20px of box is left for a line that is 22.4px tall
   (16px at 1.4). Every composer in the app was clipping its own first line
   -- the placeholder's descenders were sliced off, which is what "the text
   isn't showing fully" looked like on the phone.
   50px is that arithmetic done rather than guessed: 22.4 + 24 + 2 = 48.4.
   The mic and Send match it so the row still lines up.
   The two rules below were separate blocks setting border-radius twice,
   18px then 11px. The 18px never applied. Merged, so the value that wins is
   the value that is written. */
.chat-bar input, .chat-bar textarea {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 16px;
  line-height: 1.4;
  padding: 12px 14px;
  min-height: 50px;
  max-height: 160px;
  resize: none;
  overflow-y: hidden;
  background: var(--paper);
  color: inherit;
  border: 1px solid var(--line, #dfe4e6);
  border-radius: 11px;
  box-shadow: 0 1px 2px rgba(26, 23, 20, .04),
              0 10px 30px -22px rgba(26, 23, 20, .5);
}
.chat-bar input:focus, .chat-bar textarea:focus {
  outline: none;
  border-color: var(--accent, #0b1f4d);
}
.chat-bar input::placeholder, .chat-bar textarea::placeholder {
  color: var(--ink-3, #7c878c);
}
/* .btn is width:100% for the full-width buttons in the sheet; beside an
   input it has to stop stretching and size to its own label. */
.chat-bar .btn {
  width: auto;
  margin-top: 0;
  min-height: 50px;
  padding-inline: 18px;
  white-space: nowrap;
}
.chat-bar .voice-control { align-self: stretch; min-height: 50px; }
.chat + .chat-hint, #chatHint { display: block; padding: 0 12px 10px; }

/* Buttons under an assistant answer — download, print. */
.coach-actions { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
/* The upload control is a <label> wrapping a hidden <input type=file>, which
   is the only way to style a file picker; it therefore needs the pointer and
   the centring a real button gets for free. */
#cvPickWrap { display: block; text-align: center; cursor: pointer; }

/* ============================ site footer ============================ */
/*
  Always present, on the sign-in gate as well as inside the app. A payment
  processor's reviewer arrives signed out and follows these links to find the
  policies; so does anyone deciding whether to trust the site with a card.
  Quiet by default — this is not something a returning user should have to
  read past every day — but never hidden.
*/
.site-foot {
  max-width: 680px;
  margin: 0 auto;
  padding: 28px 16px calc(28px + env(safe-area-inset-bottom));
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px 18px;
  font-size: .76rem;
  border-top: 1px solid var(--line);
}
.site-foot a {
  color: var(--ink-3);
  text-decoration: none;
}
.site-foot a:hover,
.site-foot a:focus-visible { color: var(--accent); }

/* ============================== pay by CliQ ============================== */
/*
  Three values a person has to copy into a banking app on the same phone,
  usually while switching between two apps. So: big, monospaced, individually
  copyable, and impossible to confuse with each other.

  The amount carries a warning because it is not a price — it is an identity.
  A transfer for a "close enough" amount is a payment that has to be found by
  hand, and the user has no way to know that unless it says so here.
*/
.cliq {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

.cliq-steps {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.cliq-steps li {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.cliq-label {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-3);
  font-weight: 650;
}

.cliq-value {
  display: flex;
  align-items: center;
  gap: 8px;
}

.cliq-value code {
  font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas,
               "Liberation Mono", monospace;
  font-size: 1.15rem;
  font-weight: 600;
  /* Digits that line up between the amount and the reference, so a glance
     back and forth between screen and banking app does not lose its place. */
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  color: var(--ink);
  background: var(--accent-bg);
  border-radius: 8px;
  padding: 6px 10px;
  /* The value is the thing being copied; it must wrap rather than push the
     copy button off a narrow screen. */
  word-break: break-all;
  /* And it must be selectable even where the clipboard API is missing. */
  user-select: all;
  -webkit-user-select: all;
}

button.copy {
  flex: none;
  font: inherit;
  font-size: 1rem;
  line-height: 1;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
}
button.copy:hover,
button.copy:focus-visible { border-color: var(--accent); color: var(--accent); }

.cliq-wait {
  margin: 0 0 6px;
  font-size: .9rem;
  color: var(--ink-2);
}
/* Only the confirmation gets the accent. A page where the waiting state is
   already green has nothing left to say when the money actually arrives. */
.cliq-wait.is-paid {
  color: var(--fresh);
  font-weight: 650;
}

@media (prefers-reduced-motion: no-preference) {
  .cliq-wait:not(.is-paid)::after {
    content: "";
    display: inline-block;
    width: .5em;
    text-align: start;
    animation: cliq-dots 1.4s steps(4, end) infinite;
  }
  @keyframes cliq-dots {
    0%   { content: ""; }
    25%  { content: "."; }
    50%  { content: ".."; }
    75%  { content: "..."; }
  }
}

/* ============================ billing page ============================
   The billing sheet, promoted to a page. It keeps .sheet so every rule
   already written for its insides still applies, and .is-page overrides
   only the three things that make a sheet a sheet: the dimmed backdrop,
   the bottom alignment, and the cropped height. */
.sheet.is-page {
  background: var(--paper);
  align-items: flex-start;
  overflow-y: auto;
}
.sheet.is-page .sheet-card {
  max-width: 560px;
  max-height: none;
  border-radius: 0;
  min-height: 100dvh;
}
@media (min-width: 560px) {
  .sheet.is-page { align-items: flex-start; }
  .sheet.is-page .sheet-card { border-radius: 0; }
}

/* The two ways to pay. Buttons, not cards with buttons inside: the whole
   thing is the target, which matters most on the phone this is read on. */
.payways { display: grid; gap: 10px; margin: 4px 0 18px; }
.payway {
  display: grid; gap: 4px; text-align: start;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.payway:hover:not(:disabled) { border-color: var(--accent); }
.payway:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.payway-name { font-weight: 650; }
.payway-sub { font-size: .85rem; opacity: .8; line-height: 1.45; }
.payway-tag {
  justify-self: start;
  font-size: .72rem; letter-spacing: .04em; text-transform: uppercase;
  padding: 2px 8px; border-radius: 999px;
  background: var(--line);
}
/* Disabled, but still readable. A greyed-out option nobody can read is a
   worse answer than a clear "not yet". */
.payway:disabled { cursor: default; opacity: .72; }


/* The way out when a payment goes wrong. Quiet, at the bottom, but a real
   link rather than an address to copy: on a phone, copying one out means
   leaving the page that has the reference on it. */
.payhelp { margin-top: 18px; text-align: center; }
.payhelp a { color: var(--accent); text-decoration: underline; }

/* THE END OF THE FEED, WHICH IS USUALLY NOT THE END.

   The feed arrives thirty cards at a time and this sits after the last one.
   Normally the reader never reads it: the next page is requested a screen
   early, so by the time this scrolls into view it has already been replaced
   by more cards. It matters on a slow connection, where it is the only sign
   that something is coming rather than finished.

   It becomes a button in two cases -- a WebView with no IntersectionObserver,
   and a page that failed -- so it carries a button's affordances without
   being one by default. */
.feed-end {
  padding: 18px 12px;
  text-align: center;
  color: var(--ink-3);
  font-size: 13px;
}

.feed-end.is-button {
  cursor: pointer;
  color: var(--accent);
  font-weight: 600;
  border: 1px solid var(--line);
  border-radius: 12px;
  margin: 8px 0 4px;
  /* A tap target, not a line of text: 44px is the smallest thing a thumb
     hits reliably, and this is the one control that rescues a failed page. */
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.feed-end.is-button:hover { background: var(--accent-bg); }

/* THE TRIAL COUNTDOWN.

   A thin strip above the header. Quiet for most of the trial and marked on
   the last day, because a warning that looks identical on day one and day
   five is read on neither. It is hidden entirely for an account with no
   trial -- an ordinary free or paid user should never see a clock nobody
   gave them. */
/* THE PITCH. A card above the feed that says what the reader is looking
   at and why it is worth paying for -- with the pool's live numbers and
   their own job's. One accent, big type for the numbers, quiet
   everywhere else. On a wide screen it is a band across list + reader. */
.pitch {
  max-width: 680px; margin: 12px auto 0; padding: 20px 22px 18px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
  border-inline-start: 4px solid var(--accent);
}
.pitch-eyebrow {
  font-size: .72rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 6px;
}
.pitch-title {
  margin: 0 0 10px; font-size: 1.25rem; line-height: 1.3; font-weight: 750;
  color: var(--ink); text-wrap: balance;
}
.pitch-numbers {
  margin: 0 0 8px; font-size: .95rem; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.pitch-numbers b, .pitch-mine b { color: var(--accent); font-weight: 750; }
.pitch-mine {
  margin: 0 0 12px; padding: 10px 14px; border-radius: 10px;
  background: var(--accent-bg); color: var(--ink); font-size: 1rem;
  font-weight: 600; font-variant-numeric: tabular-nums;
}
.pitch-list {
  margin: 0 0 12px; padding: 0; list-style: none;
  display: grid; gap: 7px; font-size: .92rem; color: var(--ink);
}
.pitch-list li { display: flex; gap: 10px; align-items: flex-start; line-height: 1.45; }
.pitch-list li::before { content: attr(data-ico); flex: none; font-size: 1.05rem; line-height: 1.3; }
.pitch-price { margin: 0 0 12px; font-size: .9rem; color: var(--ink-2); }
.pitch-price b { color: var(--ink); }
.pitch-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.pitch-actions .btn { min-height: 38px; }
.pitch-actions .btn-primary {
  background: var(--action); color: var(--action-ink); border-color: var(--action);
  font-weight: 700;
}
@media (min-width: 1024px) {
  #app > .pitch { grid-column: 2 / span 2; max-width: none; margin: 18px 28px 0; }
  #app > .pitch .pitch-actions .btn { width: auto; flex: 0 0 auto; padding-inline: 26px; }
}

/* THE ACCOUNT BAR. Sits above the countdown, in the quiet brand tint
   rather than the yellow -- the yellow belongs to the one thing being
   asked for on the screen, and on a trial that is the countdown's own
   button. Wraps rather than squeezes: three words of Arabic and two
   buttons do not fit one line on a 360px phone. */
.acct-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  padding: 9px 14px;
  background: var(--accent-bg);
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  font-weight: 600;
}

.acct-bar-go { display: flex; gap: 8px; }

.acct-btn {
  border: 1.5px solid var(--accent);
  background: transparent;
  color: var(--accent);
  font: inherit;
  font-weight: 700;
  border-radius: 999px;
  /* 34px: a real tap target. The old route to both of these was a 20px
     badge in the header corner. */
  padding: 6px 15px;
  min-height: 34px;
  cursor: pointer;
}

.acct-btn.is-go {
  background: var(--action);
  border-color: var(--action);
  color: var(--action-ink);
}

.acct-btn:hover { filter: brightness(.95); }

/* The way out of the gate, for somebody who was already browsing. Quiet:
   it is an escape, not an offer. */
.gate-back {
  margin-top: 14px;
  border: 0;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: 13px;
  text-decoration: underline;
  cursor: pointer;
}

.trial-strip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 8px 14px;
  background: var(--action);
  color: var(--action-ink);
  font-size: 13px;
  font-weight: 600;
}

.trial-strip.is-last {
  background: var(--stale);
  color: #fff;
}

.trial-cta {
  border: 1px solid currentColor;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: 700;
  border-radius: 999px;
  /* 32px high in a 40px strip: a real tap target without making the strip
     itself into a banner. */
  padding: 5px 14px;
  min-height: 32px;
  cursor: pointer;
}

.trial-cta:hover { background: rgba(255, 255, 255, .18); }

/* The wall's small print sits under the buttons, not above them. */
.gate-sub.small { font-size: 12.5px; opacity: .75; margin-top: 14px; }


/* THE DAY-2 ASK.
   Quiet on purpose. It sits under the countdown, in the same family of
   colours, and never covers the jobs -- a guest who ignores it must lose
   nothing, or the trial itself starts feeling like a form to fill in. */
.email-ask {
  margin: 0 auto 10px;
  max-width: 640px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
}
.email-ask p { margin: 0 0 8px; font-size: 14px; }
.email-ask-row { display: flex; gap: 8px; }
.email-ask-row input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 9px 10px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--paper);
  color: inherit;
  font: inherit;
}
.email-ask-row button {
  flex: 0 0 auto;
  padding: 9px 14px;
  border: 0;
  border-radius: 9px;
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.email-ask-note { margin: 8px 0 0; font-size: 13px; }
.hdr-tg { color: var(--top-ink); text-decoration: none; }
.hdr-tg svg { display: block; }
.follow-btns { display: flex; gap: 8px; flex-wrap: wrap; }
.follow-btn {
  flex: 1 1 140px; display: block; padding: 10px 12px; border-radius: 9px;
  text-align: center; font-weight: 700; text-decoration: none; color: #fff;
}
.follow-btn.tg { background: #229ed9; }
.follow-btn.fb { background: #1877f2; }
.follow-btn:hover { text-decoration: none; filter: brightness(1.06); }
.email-ask-note.is-bad { color: var(--bad); }
/* Saying no must be as easy as saying yes, and look it. */
.email-ask-tg {
  display: block; margin: 8px 0 2px; font-size: .84rem; font-weight: 600;
  color: var(--accent); text-decoration: none;
}
.email-ask-tg:hover { text-decoration: underline; }

.email-ask-no {
  margin-top: 6px;
  padding: 4px 0;
  border: 0;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: 13px;
  text-decoration: underline;
  cursor: pointer;
}

/* THE INSTALL STRIP.
   Sits above the header, in the same family as the trial strip, and is
   never allowed to cover the jobs -- somebody who ignores it forever must
   lose nothing. The APK variant is quieter still: it is offered to people
   who already installed the web app, so it has already earned its place
   and does not need to shout. */
.install-strip {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--accent-bg);
  color: var(--ink);
  font-size: 14px;
}
.install-strip.is-apk {
  background: var(--line-2);
  font-size: 13px;
}
.install-strip span { flex: 1 1 180px; min-width: 0; }
.install-go {
  flex: 0 0 auto;
  padding: 8px 14px;
  border: 0;
  border-radius: 9px;
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.install-no {
  flex: 0 0 auto;
  padding: 8px 4px;
  border: 0;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: 13px;
  text-decoration: underline;
  cursor: pointer;
}

/* THE iOS SHEET. Safari fires no install event and never will, so this is
   the only honest answer: show where the button they need actually is. */
.ios-sheet {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.45);
}
.ios-card {
  width: 100%;
  max-width: 380px;
  padding: 20px;
  border-radius: 16px;
  background: var(--card);
  color: var(--ink);
}
.ios-card h2 { margin: 0 0 12px; font-size: 18px; }
.ios-steps { margin: 0 0 16px; padding-inline-start: 20px; }
.ios-steps li { margin-bottom: 8px; font-size: 14px; }

/* ------------------------- the crawlable hero -------------------------
   #seoHero is the only text on this domain a crawler can read: the gate,
   the app and the feed are all either `hidden` until app.js runs or behind
   a session, so the fetched body was otherwise empty.

   app.js removes the element outright the moment scripting runs, so these
   rules are seen by exactly two visitors: a crawler, and somebody with
   JavaScript off who would otherwise get a blank white page. It is styled
   properly rather than hidden off-screen because off-screen keyword text
   is cloaking -- this is real content that a real reader can read. */
.seo-hero {
  max-width: 640px;
  margin: 0 auto;
  padding: 40px 20px 8px;
  color: var(--ink-2);
  font-size: .95rem;
  line-height: 1.7;
}
.seo-hero h1 {
  font-family: var(--serif);
  font-size: 1.6rem;
  line-height: 1.35;
  color: var(--ink);
  margin: 0 0 14px;
}
.seo-hero h2 {
  font-size: 1rem;
  color: var(--ink);
  margin: 22px 0 6px;
}
.seo-hero ul { margin: 6px 0; padding-inline-start: 20px; }
.seo-hero p { margin: 0 0 10px; text-wrap: pretty; }
.seo-hero a { color: var(--accent); }


/* =============================== desktop ===============================
   REPORTED: "the design in desktop is bad". It was: one 680px phone column
   dropped into the middle of a 1920px screen, with the header stacked on
   top of it exactly as on a phone -- two thirds of the screen were paper.

   On a wide screen the header becomes a SIDEBAR: the mark, the country
   and job, the three actions and the account sit down the side and stay
   put while the feed scrolls. The feed takes the rest, two cards abreast
   when there is room. Nothing below this width changes: the phone layout
   is the design, this is the same design given the room it was denied.

   In Arabic the grid mirrors itself: column one is on the right, so the
   sidebar sits where an Arabic reader starts. */
@media (min-width: 1024px) {
  /* ONLY THE JOBS SCROLL. The sidebar and the reader are sticky, and
     sticky was silently broken: `overflow-x: hidden` on html and body
     (above, for the phone) turns body into a scroll container, so the
     two panes stuck to a box that never scrolls and rode off the top
     with the page. `clip` cuts the overflow without making a scroll
     container, and the panes stay where they are while the list moves. */
  html, body { overflow-x: clip; }
  #app:not([hidden]) {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    max-width: 1480px;
    margin: 0 auto;
    min-height: 100vh;
    border-inline: 1px solid var(--line-2);
    background: var(--paper);
  }
  #app > * { grid-column: 2; }

  #app > .top {
    grid-column: 1;
    grid-row: 1 / span 99;
    position: sticky; top: 0; align-self: start;
    box-sizing: border-box; height: 100vh; overflow-y: auto;
    display: flex; flex-direction: column; gap: 18px;
    padding: 26px 22px 22px;
    background: var(--top);
    border-bottom: 0;
  }
  .top-row {
    flex-direction: column; align-items: stretch;
    gap: 16px; padding: 0; max-width: none; margin: 0;
  }
  .top-row > .mark { height: 26px; }
  .brand svg { width: 26px; height: 26px; }
  .brand-word { font-size: 1.5rem; }
  .top-id { order: 0; }
  .market { font-family: var(--serif); font-size: 1.35rem; font-weight: 500;
            letter-spacing: 0; white-space: normal; line-height: 1.25; }
  .poolline { white-space: normal; margin-top: 3px; }
  .top-actions { justify-content: space-between; margin: 0; }
  .plan { flex: 1 1 auto; justify-content: space-between; }

  .quicksearch {
    flex-direction: column; gap: 8px; padding: 0; max-width: none; margin: 0;
  }
  .quicksearch select { padding: 10px 12px; font-size: .9rem; }

  .filters {
    flex-direction: column; gap: 8px; overflow: visible;
    padding: 0; max-width: none; margin: 0;
  }
  .filters.secondary { margin-top: 0; }
  .filters .chip {
    width: 100%; justify-content: flex-start;
    padding: 11px 14px; font-size: .9rem; border-radius: 10px;
  }

  /* THE LIST AND THE READER (see app.js, "wide screens"). The feed is a
     column of short rows, 440px, and the reader takes the rest: the job
     that was clicked, in full, and it stays put while the list scrolls.
     One post is read at a time and nothing on the screen is empty. */
  #app:not([hidden]) { grid-template-columns: 300px 440px minmax(0, 1fr); }
  #app > * { grid-column: 2 / span 2; }
  #app > .top { grid-column: 1; }
  #app > .feed {
    grid-column: 2;
    max-width: none; margin: 0; padding: 0 0 48px;
    display: flex; flex-direction: column; gap: 0;
    border-inline-end: 1px solid var(--line);
  }
  #app > .reader {
    grid-column: 3;
    position: sticky; top: 0; align-self: start;
    box-sizing: border-box; max-height: 100vh; overflow-y: auto;
    padding: 22px 28px 40px;
  }
  .reader .card { padding: 22px 26px; }
  .reader .card-text { font-size: 1rem; line-height: 1.7; }
  .reader .card-foot .foundon { margin-inline-start: auto; }

  .row {
    display: flex; flex-direction: column; gap: 6px; width: 100%;
    padding: 14px 18px; text-align: start;
    background: none; border: 0; border-bottom: 1px solid var(--line-2);
    color: var(--ink); font: inherit; cursor: pointer;
  }
  .row:hover { background: var(--card); }
  .row.is-on {
    background: var(--card);
    box-shadow: inset 3px 0 0 var(--accent);
  }
  [dir="rtl"] .row.is-on { box-shadow: inset -3px 0 0 var(--accent); }
  .row-top { display: flex; align-items: center; gap: 8px; }
  .row-title {
    font-size: .93rem; font-weight: 600; line-height: 1.45;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; word-break: break-word;
  }
  .row .tags { margin-top: 0; }
  .feed .skel { margin: 12px 18px; }
  .feed .feed-end { margin: 12px 18px; }

  /* Strips that used to span the screen now span the feed and reader. */
  .trial-strip, .install-strip, .email-ask { margin: 0; }
}

@media (min-width: 1480px) {
  #app:not([hidden]) { box-shadow: var(--shadow); }
}
