/*
 * Application-wide base: the design tokens and the element defaults every
 * screen inherits. Component classes and card themes are stage 4 (theme
 * record = tokens JSON + contract CSS, validated by whitelist) and do not
 * belong here.
 *
 * Direction is never hard-coded. Use logical properties — margin-inline,
 * padding-block, inset-inline-start, text-align: start — so one stylesheet
 * serves Hebrew and English from the dir attribute on <html>.
 */

/* The signed-in screens' set, and theirs alone (#183). The public card
   carries its own copy in card.css, scoped to its layout's
   html.nadlan-card-root; changing a value here moves no card on the air.

   Light is what the product ships (#187, Erez's ruling of 2026-09-05);
   dark is a press in the side bar, written as data-theme on <html>. The
   dark screens everybody had until now were Adam's and temporary — he
   cannot work on a light design — and every value in the dark block below
   is the one that was here, unchanged, so nothing about his screens moves.

   Not a media query. Adam's call of 2026-09-04 holds in its new form: the
   look is the realtor's own choice on their own account, rather than
   whatever their device happens to be set to.

   THE RULE THIS BLOCK EXISTS TO ENFORCE: a colour is written once, here,
   under a name that says what it means. A literal colour anywhere else in
   this file is a colour that cannot follow the look, and turning the app
   light was three days of finding eighty-three of them. Reach for an
   existing meaning before adding a name.

   color-scheme tells the browser to render its own controls to match — the
   text field, the scrollbar, the focus ring. The viewport takes it from the
   root element, which is why data-theme is on <html> and not on <body>. */
:root {
  color-scheme: light;

  /* Type and shape: the same in both looks. Light and dark is a question
     about colour, and a radius that moved with it would be a second
     design rather than the same one lit differently. */
  --v-font: "Heebo", "Roboto", system-ui, -apple-system, "Segoe UI", sans-serif;
  --v-font-size: 16px;
  --v-line-height: 1.65;
  --v-radius: 14px;
  --v-gap: 1rem;

  /* The acting banner (#467): the same in every look and palette, so no
     look can take its contrast away; no other block names these. */
  --v-acting-bg: #ffd23f;
  --v-acting-ink: #1a1a1a;
  --v-acting-on-ink: #fff;

  /* Ink and surfaces. The light set is the card's own `paper` palette from
     db/seeds/card_themes.yml — already drawn by hand and already checked at
     4.5:1 — rather than a second light palette nobody has looked at. */
  --v-ink: #14161a;
  --v-ink-muted: #5b6472;
  --v-accent: #1f5fd0;
  --v-surface: #ffffff;
  --v-page: #f4f5f7;
  --v-line: #e2e5ea;
  /* The ground inside a box a realtor types into, and behind the tabs and
     the picture frame that are not typed into but are still something to
     press (#201, Adam's hand test 2026-09-19). A white box on a white panel
     was a thin line and nothing else. Deeper here than the first value the
     issue shipped with: the tabs and the picture frame sit on --v-page, not
     on a panel, and at #eef1f5 the ground was 1.04:1 against it — a step
     the eye does not find. */
  --v-field: #e6eaf1;
  --v-shadow: 0 1px 2px rgba(16, 20, 28, .06), 0 8px 24px rgba(16, 20, 28, .08);

  /* What went wrong: a refusal, a red field, a destructive press.
     -strong is the saturated edge a field or a "remove" wears; -line and
     -bg are the tinted box the alerts and the failed pill sit in. */
  --v-danger: #b3261e;
  --v-danger-strong: #c62828;
  --v-danger-line: #f2b8b5;
  --v-danger-bg: #fdeceb;

  /* What went right: saved, published, up to date, a valid field.
     -soft is the tone that sits on --v-ok-bg rather than on the page;
     -wash and -badge are the translucent tints a live card row and its
     state pill wear, so they follow the ground rather than assuming one. */
  --v-ok: #0f7a45;
  --v-ok-soft: #146c43;
  --v-ok-strong: #1e8e4f;
  --v-ok-line: #a6d9bd;
  --v-ok-bg: #e8f5ed;
  --v-ok-wash: rgba(15, 122, 69, .1);
  --v-ok-wash-line: rgba(15, 122, 69, .35);
  --v-ok-badge: rgba(15, 122, 69, .16);

  /* "Publish" — the fourth screen's press and the finish tab. A meaning
     colour, fixed in every look and in every palette #188 brings, the way
     red means removal (#197, Adam, 2026-09-20): a press that changed
     colour because a realtor picked a palette for their own screens would
     stop being the green they were taught to look for. Chosen against
     making it a look token a palette swaps.
     The words on it are black, not white. The press was #2f8f5b with
     white words: 4.04:1, and the tab's label is .9rem, which is not large
     text and gets no discount. Black on that green is 5.2:1 and near-black
     #1a1a1a is 4.31:1, so it has to be black — chosen against darkening
     the green to #2a7f51, which passes with white words but is not the
     green Adam picked.
     Then the fill was lightened on Adam's hand test, 2026-09-20 ("make the
     green lighter its too dark"), which is why the fill and the edge are
     two names. A filled press has two jobs: carry its words, and show
     where it is. One colour cannot do both much lighter than this — the
     old #2f8f5b is 3.70:1 on --v-page, and a single colour one step
     lighter than the fill below drops the whole press under the 3:1 an
     edge is built to. Split, the fill is free to be light (black on
     #3bb072 is 7.64:1) and the edge keeps the green that draws the
     shape. */
  --v-go: #3bb072;
  --v-go-line: #2f8f5b;
  --v-on-go: #000000;

  /* LinkedIn's mark in the links step's rows. One name, two values, as
     every colour on these screens has had since #187: the lightened blue
     was picked to sit apart from Facebook's on a near-black page and comes
     to 2.54:1 on a white one, so the light screens get LinkedIn's own
     brand blue. Fixed like the green — it is LinkedIn's colour, not the
     look's, so no palette may swap it. The other three marks read on
     either ground and stay literals in their rules. */
  --v-linkedin: #0a66c2;

  /* Saved with a reservation: a draft, a box at its limit, a language
     whose words have gone stale. Amber is the tone that cannot simply be
     darkened from its dark-screen value: #e0b21e on white is about 1.9:1,
     so the light set drops most of the way to brown to clear 4.5:1. */
  --v-warn: #8a6100;
  --v-warn-soft: #7a5600;
  --v-warn-strong: #8a4e00;
  --v-warn-line: #e7cf9a;
  --v-warn-bg: #fdf4e0;
  --v-warn-wash: rgba(176, 106, 0, .1);
  --v-warn-wash-line: rgba(176, 106, 0, .35);
  --v-warn-badge: rgba(176, 106, 0, .16);

  /* The presses that only go somewhere, in the accent's own family, and
     the lavender the account page's tray uses for "the card itself". */
  --v-accent-soft: #1a4fa8;
  --v-accent-line: #b6c9ee;
  --v-soft-ink: #5b3fa8;
  --v-soft-line: #d3c8ee;
  /* The words on the one filled accent press. White until #187, which on
     the dark screens' lighter blue is 3.2:1 — under AA, on the most
     pressed button in the product. One blue cannot both carry white words
     and read as a link on a near-black page, so the label gets a name of
     its own and each look answers the question separately. */
  --v-on-accent: #ffffff;

  /* The 16% wash of the accent: the row of the page the realtor is on
     in the side bar, the main language's band on the languages page,
     the strip that says a screen is in another language, and a picked
     choice in the creation pop-up. One name, because a band the words
     on it are measured against cannot be spelled out in four rules.
     Written as rgba rather than color-mix for the same reason the
     other washes are: the pair is checked by reading this file. */
  --v-accent-wash: rgba(31, 95, 208, .16);

  /* The words that sit on that wash. One name, two values, like
     --v-on-accent beside it: the accent itself on its own 16% wash is
     4.40:1 on the dark screens, under AA, because #187 lightened the
     blue and the wash lightened the ground with it. The light half is
     the accent unchanged at 4.61:1; the dark half is --v-accent-soft's
     lighter blue, 6.41:1 (#214). */
  --v-accent-on-wash: #1f5fd0;

  /* Structure with no meaning of its own: the tray under a card row, the
     frame round an editor field, the lines between the side bar's rows. */
  --v-tray: #eef0f3;
  /* Darkened with --v-field: an edge is built to 3:1 against the ground it
     is drawn on, and the deeper field ground spends the margin the old
     value had. On the white panel this reads at 4.36:1 rather than 3.6:1,
     which is the same change in the direction the standard wants. */
  --v-frame: #6e7a8a;
  --v-divider: #e2e5ea;
}

/* Adam's screens, and anyone else's who presses the moon (#187). Every
   value here is what :root held before the light default arrived. */
:root[data-theme="dark"] {
  /* The acting banner's own three, the same as in the light block (#467). */
  --v-acting-bg: #ffd23f;
  --v-acting-ink: #1a1a1a;
  --v-acting-on-ink: #fff;
  color-scheme: dark;

  --v-ink: #e7e9ec;
  --v-ink-muted: #98a1ad;
  --v-accent: #4c8dff;
  --v-surface: #17191d;
  --v-page: #0f1114;
  --v-line: #2a2f36;
  /* A step up from the panel here, where light steps down: on a near-black
     screen a recess is lighter than what surrounds it, not darker. */
  --v-field: #22262c;
  --v-shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 8px 24px rgba(0, 0, 0, .35);

  --v-danger: #ff9b93;
  /* #d4574b until #187, which is 4.41:1 on the dark surface: under AA, and
     this tone is the "remove" link's words as well as an invalid field's
     edge. Lifted two steps to clear 4.5:1. */
  --v-danger-strong: #e06a5e;
  --v-danger-line: #5c2f2a;
  --v-danger-bg: #2a1a18;

  --v-ok: #6fdf9f;
  --v-ok-soft: #8fe0b0;
  --v-ok-strong: #3fa96e;
  --v-ok-line: #2f5c3f;
  --v-ok-bg: #172a1f;
  --v-ok-wash: rgba(63, 169, 110, .12);
  --v-ok-wash-line: rgba(63, 169, 110, .4);
  --v-ok-badge: rgba(63, 169, 110, .25);

  /* The same green and the same black words on both screens: it means
     "publish" rather than following a look. */
  --v-go: #3bb072;
  --v-go-line: #2f8f5b;
  --v-on-go: #000000;

  --v-linkedin: #5aa9e6;

  --v-warn: #e0b21e;
  --v-warn-soft: #e0c46a;
  --v-warn-strong: #f5b455;
  --v-warn-line: #5c4d1e;
  --v-warn-bg: #2a2414;
  --v-warn-wash: rgba(224, 138, 30, .12);
  --v-warn-wash-line: rgba(224, 138, 30, .4);
  --v-warn-badge: rgba(224, 138, 30, .25);

  --v-accent-soft: #7fb0ff;
  --v-accent-line: #2f4a7a;
  --v-soft-ink: #c9b8ff;
  --v-soft-line: #4a3f7a;
  --v-on-accent: #0b1220;

  --v-accent-wash: rgba(76, 141, 255, .16);
  /* --v-accent-soft's blue: the accent itself is 4.40:1 on its wash here. */
  --v-accent-on-wash: #7fb0ff;

  --v-tray: #1f2228;
  --v-frame: #6b7480;
  --v-divider: #3a414b;
}

*, *::before, *::after { box-sizing: border-box; }

/* Read aloud, never drawn: text a screen reader needs and the screen does
   not (the languages table's column names, #164; an empty picture box
   on a computer, which shows a drag line instead, #430). */
.v-sr-only, .v-image-none {
  position: absolute; inline-size: 1px; block-size: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

body {
  margin: 0;
  background: var(--v-page);
  color: var(--v-ink);
  font-family: var(--v-font);
  font-size: var(--v-font-size);
  line-height: var(--v-line-height);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { line-height: 1.25; letter-spacing: -.01em; margin-block: 0 .5em; }

a { color: var(--v-accent); }

img, svg { max-inline-size: 100%; block-size: auto; }

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

/* A number inside a Hebrew sentence keeps its own direction. Phone numbers,
   prices and licence numbers all need this or their segments reorder. */
.v-num { direction: ltr; unicode-bidi: isolate; font-variant-numeric: tabular-nums; }

/* Screens. Kept small on purpose: real components are the card contract in
   stage 4, and everything here is the login flow's own furniture. */

.v-shell { max-inline-size: 30rem; margin-inline: auto; padding: 3rem 1.25rem; }

.v-card {
  background: var(--v-surface);
  border: 1px solid var(--v-line);
  border-radius: var(--v-radius);
  box-shadow: var(--v-shadow);
  padding: 1.75rem;
}

.v-title { font-size: 1.35rem; margin-block-end: 1.25rem; }
/* The icon before the words on a press, a tab, a title or a strip (#68).
   The side bar's entries are the size reference — an icon there is 1.15x
   the words beside it — and this is em rather than rem so the proportion
   holds in a 1.35rem title as in the .8rem press of the account page's
   tray. No colour of its own: the icon takes the thing's, so a blue press
   keeps a blue icon and no new colour enters the product.

   Spacing comes from the row that holds it wherever that row is flex with
   a gap already (.v-step, .v-lang-strip, and .v-pane-tab below); a title, a
   press, a field's label and a design section's heading lay their children
   out inline, so those ask for a margin of their own. */
.v-icon-lead { font-size: 1.15em; }
:is(.v-title, .v-btn, .v-label, .v-design-heading) > .v-icon-lead { margin-inline-end: .4rem; }

.v-note { color: var(--v-ink-muted); margin-block: 0; }
.v-note strong { color: var(--v-ink); }
.v-note--stacked strong { display: block; }
.v-note--stacked { margin-block-end: 1.25rem; }
.v-subtitle { font-size: 1rem; color: var(--v-ink-muted); margin-block: 0 .75rem; }
.v-accent { color: var(--v-accent); }
.v-signed-in-as { margin: 0 0 1rem; font-size: .85rem; color: var(--v-ink-muted); }
.v-editing-line { margin: 0; }
/* The language being edited, over a language's long form (#156, #163),
   blue so it is not taken for the main language's editor. The words say it
   too, never the colour alone. */
.v-lang-strip {
  display: flex; align-items: center; gap: .6rem; margin: 0 0 1rem; padding: .55rem .8rem;
  border: 1px solid var(--v-line); border-inline-start-width: 4px; border-radius: 6px;
  color: var(--v-ink); font-size: .9rem;
}
.v-lang-strip--other { border-color: var(--v-accent); background: var(--v-accent-wash); font-weight: 600; }
/* The main language's own strip in the editor (Adam, 2026-09-17): the
   page's lines, not the blue that means another language. */
.v-lang-strip--main { background: color-mix(in srgb, var(--v-ink) 6%, transparent); }
/* The way back sits at the strip's far end. On the long form it submits
   the form (#170), so there it is a button wearing the link it used to
   be; the editor's own strip keeps the plain link it has always had. */
.v-lang-strip-back { margin-inline-start: auto; white-space: nowrap; }
button.v-lang-strip-back {
  padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; color: var(--v-accent); text-decoration: underline;
}

/* The card's address as it will be printed, under the address field. */
.v-address-preview { margin: .5rem 0 0; font-size: .95rem; overflow-wrap: anywhere; }
.v-address-preview.is-example { color: var(--v-ink-muted); }
.v-address-tail { color: var(--v-warn); font-weight: 600; }

/* The realtor's cards on the account page. Two boxes per card (Adam,
   2026-09-08): the tinted one holds the address with its label at the
   start and the badge glued to the end, nothing else; a grey tray hangs
   off its bottom edge, flush, with every press in one line. The list
   carries its own label above it, quieter than the page's own name. */
.v-cards-label { margin: 0 0 .5rem; color: var(--v-ink-muted); font-size: .9rem; }
.v-your-cards { list-style: none; margin: 0 0 1.25rem; padding: 0; display: grid; gap: .8rem; }
.v-your-card { --v-card-pad: .9rem; }
.v-your-card-box {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: .6rem var(--v-card-pad);
  padding: var(--v-card-pad);
  border: 1px solid var(--v-line);
  border-radius: var(--v-radius) var(--v-radius) 0 0;
}
.v-your-card--live .v-your-card-box { background: var(--v-ok-wash); border-color: var(--v-ok-wash-line); }
.v-your-card--draft .v-your-card-box { background: var(--v-warn-wash); border-color: var(--v-warn-wash-line); }
/* Hidden by the system (#278 round 9): a modifier beside the row's own
   class rather than in place of it, so the box reads off the air while the
   tray keeps the layout a published card's presses are laid out with. Last
   of the three, so it wins on a card that is published and hidden.
   Named for whose act it is, and not `--hidden`, which stood one character
   from `.v-your-card-hidden`, the line's own class (the stranger's pass). */
.v-your-card--admin-hidden .v-your-card-box { background: var(--v-warn-wash); border-color: var(--v-warn-wash-line); }
.v-your-card-main { display: flex; align-items: baseline; gap: .5rem; min-inline-size: 0; flex-wrap: wrap; }
.v-your-card-label { color: var(--v-ink-muted); font-size: .85rem; }
.v-your-card-box > .v-state { justify-self: end; }
/* The tray: the standard grey box, its top edge shared with the tinted
   one above it, the presses spread evenly across one line. */
.v-your-card-actions {
  display: flex; justify-content: space-evenly; align-items: center; gap: .4rem;
  padding: .7rem var(--v-card-pad);
  /* A shade lighter than the page's boxes, so the tray reads as its own
     thing under the tinted box (Adam, 2026-09-08). */
  background: var(--v-tray);
  border: 1px solid var(--v-line); border-block-start: 0;
  border-radius: 0 0 var(--v-radius) var(--v-radius);
}
/* button_to wraps its button in a form; the form takes no room of its own. */
.v-your-card-actions form { display: contents; }
/* Five presses since #163, and they no longer fit the phone-width box
   (#168; Adam, 2026-09-18, like the languages page, against a menu and
   against fewer presses). Every press is as wide as its own icon and
   words, never stretched to fill a row, and the presses share a row while
   they fit, wrapping whole to the next only when they do not (#321,
   Adam's phone look at a draft, where edit spanned the top row alone and
   delete the next). A stretch reads as the press to make (#304, round 1);
   wrapping by width keeps every row's presses their own size instead.

   The type, the padding and the icon's own gap are the phone's: a press
   was .8rem in a sixth-of-the-box column until #303 and drew 57px tall
   against the 33px one line asks for. The padding is a little more than
   the words need, so a press does not read as tight (Adam's look at #411,
   round 2). */
.v-your-card-actions { --v-tray-gap: .35rem; flex-wrap: wrap; gap: var(--v-tray-gap); }
.v-your-card-actions .v-btn.v-btn--small {
  flex: none;
  display: flex; align-items: center; justify-content: center; text-align: center;
  white-space: nowrap; font-size: .7rem; padding: .4rem .45rem;
}
/* The gap the icon takes from the words is the page's .4rem everywhere
   else; here it is room the longest press has not got. */
.v-your-card-actions .v-btn.v-btn--small > .v-icon-lead { margin-inline-end: .25rem; }
/* The wide screen has room for the five on one line (round 4 of Adam's
   look at #304, 2026-09-29): the box grows to the presses, and they take
   the page's type and padding. */
@media (min-width: 48rem) {
  .v-shell--account { max-inline-size: 46rem; }
  .v-your-card-actions { --v-tray-gap: .4rem; }
  .v-your-card-actions .v-btn.v-btn--small { font-size: .8rem; padding: .4rem .6rem; }
  .v-your-card-actions .v-btn.v-btn--small > .v-icon-lead { margin-inline-end: .4rem; }
}
.v-your-card-name { font-weight: 500; overflow-wrap: anywhere; }
/* The card itself under its row and tray (#409): the editor's phone, with
   room above it so its heading is not read as part of the tray. */
.v-your-card-preview { margin-block-start: 1.5rem; }
/* Not on a phone (Adam's look at #410/#411): below the editor's 64rem the
   app is in its phone layout, and there the row and its presses are the
   page. */
@media (max-width: 63.99rem) {
  .v-your-card-preview { display: none; }
}
a.v-btn { text-decoration: none; }
.v-state { font-size: .8rem; padding: .15rem .55rem; border-radius: 999px; border: 1px solid currentColor; }
/* Archived (#427) wears the draft's amber: off the air, and coming back. */
.v-state--draft, .v-state--archived { color: var(--v-warn-strong); background: var(--v-warn-badge); }
.v-state--live { color: var(--v-ok-soft); background: var(--v-ok-badge); }
/* Hidden by admin, on an admin row (#251 round 4). An opaque surface rather
   than the translucent badge the other two wear: this pill also sits on the
   blocked row's red wash, and a tint that took the wash with it came out at
   4.4:1 there, under AA. On --v-danger-bg the ink is 5.7:1 in the light
   palette and 8.2:1 in the dark one, whatever the row beneath it. */
.v-state--hidden { color: var(--v-danger); background: var(--v-danger-bg); }

/* Field-level messages, under the field they belong to. */
.v-field-error { margin: .45rem 0 0; font-size: .85rem; color: var(--v-danger); }
/* The live one under a box is always rendered (#95); empty, it takes no room. */
.v-field-error:empty { margin: 0; }
/* The server's line under a field steps aside while the live check is
   red, so a refused save never shows the same message twice (Adam,
   2026-09-07). It is back the moment the live check is not. */
/* Not the picture box itself: the agency's name sits inside the logo's box
   (#448), and its red box is no reason to hide the logo's refusal. */
/* Only while the live check says something: a box red with no words of
   its own (a count over the cap) leaves the server's line to say why
   (#444 sweep). A link row's live line speaks for its address and its
   type (taken, too many): the name's server line stays. */
.v-field:not(.v-image-field):has(.v-hint--bad:not(:empty), [data-field-limit-target=message]:not(:empty)) [data-server-error],
.v-link-row:has(.v-hint--bad:not(:empty)) [data-server-error]:is([data-field-error-attribute-value=url], [data-field-error-attribute-value=kind]) { display: none; }
/* A box the server refused wears no green "ok" of a live check that
   passes it: the refusal stands until the box changes (#444 sweep). */
.v-field:has(.is-refused) .v-hint--ok, .v-link-row:has(.is-refused) .v-hint--ok { display: none; }
/* Two classes: the plain .v-alert rule comes later in this file and was
   winning back its red (Adam, 2026-09-07, third time he asked). */
.v-alert.v-alert--ok { background: var(--v-ok-bg); border-color: var(--v-ok-line); color: var(--v-ok-soft); }
/* Saved, with a note: earlier steps hold something publish will refuse. */
.v-alert.v-alert--warn { background: var(--v-warn-bg); border-color: var(--v-warn-line); color: var(--v-warn-soft); }
/* A refused press, in the plain alert's own red, named rather than left
   to the later rule so the tone is read off the class (#164). */
.v-alert.v-alert--bad { background: var(--v-danger-bg); border-color: var(--v-danger-line); color: var(--v-danger); }

/* Required / optional tags after a label, and the live counter under a field. */
.v-required { color: var(--v-danger); font-size: .8rem; }
.v-optional { color: var(--v-ink-muted); font-size: .8rem; }
.v-counter { margin: .3rem 0 0; font-size: .78rem; color: var(--v-ink-muted); text-align: end; }
/* The line under a label and above its box (the second phone's "calls
   only"): closer to the label, further from the box (Adam, 2026-09-09).
   Two classes, because the general .v-hint rule below sets the same
   margins and came later. */
.v-hint.v-hint--above { margin-block: -.25rem .5rem; color: var(--v-ink-muted); }

/* A label with an info toggle beside it, and the box the toggle opens. */
.v-label-row { position: relative; display: flex; align-items: baseline; gap: .5rem; }
.v-label-row .v-label { margin-block-end: .6rem; }
/* The box opens under the whole label row, flush with the field's edges,
   so on a phone it never runs off the screen (Adam, 2026-09-07). */
.v-info { position: static; }
.v-info-toggle { list-style: none; cursor: pointer; color: var(--v-ink-muted); font-size: .95rem; }
.v-info-toggle::-webkit-details-marker { display: none; }
.v-info[open] .v-info-toggle { color: var(--v-accent); }
.v-info-box {
  position: absolute; inset-inline: 0; top: 1.6rem; z-index: 2; max-inline-size: 22rem;
  padding: .8rem 1rem; font-size: .85rem;
  background: var(--v-surface); border: 1px solid var(--v-line); border-radius: var(--v-radius); box-shadow: var(--v-shadow);
}
.v-info-title { margin: 0 0 .4rem; font-weight: 600; }
.v-info-box p { margin: 0; }
.v-info-box ul { margin: 0; padding: 0; list-style: none; display: grid; gap: .2rem; }
.v-info-box li { white-space: nowrap; }
.v-required[hidden] { display: none; }
textarea.v-input { resize: none; }
/* The counter's colour says where the text stands: grey at 0, green while
   there is room, yellow at the limit, red past it (Adam, 2026-09-07). */
.v-counter--some { color: var(--v-ok); }
.v-counter--full { color: var(--v-warn); }
.v-counter--over { color: var(--v-danger); font-weight: 600; }

/* Step buttons, together at the reading start (right in Hebrew): back
   first, then the forward button beside it.

   One row, always (Adam, 2026-09-21, his #227 hand test: "the bottom
   buttons of every tab should all be on the same row, you can make em
   smaller if you need"). The two names (since #434 each the step it goes
   to, "חזרה לפרטים" beside "המשך לפרטי קשר") are wider than a 360px
   screen at the buttons' full size, so the row wrapped and
   the forward press fell under the way back — two presses a thumb reaches
   in two places, on the layout every realtor uses. Smaller is what he
   chose over a shorter word, so the words are untouched and the presses
   give up padding instead.

   Two classes, not one: .v-actions is set further down this file and
   would win at the same specificity, putting the wrap back — the trap
   this file already documents for .v-btn--icon and .v-btn--small (#77). */
.v-actions.v-actions--steps { justify-content: flex-start; flex-wrap: nowrap; }
@media (max-width: 30rem) {
  /* The sides give way, never the top and bottom: a press must stay the
     height a thumb reaches. And the words may still break inside a press
     rather than run off the screen, which is what holds at 200% text
     (IS 5568 / WCAG 2.0 AA 1.4.4) — the row stays one row and grows
     taller instead (the stranger's pass, 2026-09-21). */
  .v-actions--steps .v-btn { padding: .7rem .7rem; font-size: .9rem; min-inline-size: 0; }
  /* A press whose name wraps (#434: "המשך לפרטי קשר" beside "חזרה לפרטים"
     at 320px) grows taller, and the one beside it grows with it, its name
     centred: two presses of one height, never one hanging lower. */
  .v-actions.v-actions--steps { align-items: stretch; }
  .v-actions--steps .v-btn { display: flex; align-items: center; justify-content: center; text-align: center; }
}

/* The editor's three steps: a row of tabs that also says where you are. */
/* The step that just arrived fades in. Only opacity moves, so nothing
   slides under a press that lands while it plays: the glide this replaced
   moved the whole page for 700ms and swallowed presses (Erez's stage 3
   review). */
@keyframes v-step-in { from { opacity: 0 } to { opacity: 1 } }
#card_editor > * { animation: v-step-in .18s ease-out both; }
@media (prefers-reduced-motion: reduce) { #card_editor > * { animation: none } }

/* The tabs wrap rather than squeeze: a row that only ever shrinks pushes a
   word out of its box (Adam's hand test, twice: "פרטי התקשרות" at four tabs
   and again at five), and scrolling would hide סיום, which is the press the
   whole flow leads to.

   Four to a row, counted rather than fitted. The design step (#186) made
   seven tabs, and a column count the browser works out from the space it
   has put finish alone on a line of its own — at 360px and again at
   1400px — which is the full-width bar #177 took away (Adam's hand test,
   2026-09-17). Four columns land the last three tabs on one row at every
   width, so finish is a tab among tabs wherever the editor is opened. */
/* The welcome line above the tabs, until the card first goes on the air
   (#72). Plain text, not a box and not an alert: it says where a realtor
   is, it never asks for a press. It wraps on a phone rather than being
   cut, and the icon sits on the line's own baseline. */
.v-editor-welcome {
  display: flex; align-items: baseline; gap: .45rem;
  margin: 0 0 1rem; font-size: .9rem; line-height: 1.5; color: var(--v-ink-muted);
}
.v-editor-welcome i { color: var(--v-accent); flex: none; }
/* One wording per layout. The switch is made at the editor's own 64rem
   breakpoint, further down this file — the breakpoint that decides
   whether the preview is a pane beside the editor or a tab. `display:
   none` takes the wording that does not apply out of the accessibility
   tree as well as off the screen, so a screen reader is read one of the
   two and never both. */
.v-editor-welcome--beside { display: none; }
.v-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: .4rem; margin: 0 0 1.5rem; }
/* A tab takes the field ground too (Adam's hand test, 2026-09-19): a tab
   is something to press, and on the page's own colour it read as a word
   with a line round it. The finish tab's green overrides this below. */
.v-step {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .2rem;
  padding: .5rem; font-size: .9rem; text-decoration: none;
  color: var(--v-ink-muted); background: var(--v-field);
  border: 1px solid var(--v-line); border-radius: var(--v-radius);
}
.v-step--current { color: var(--v-ink); border-color: var(--v-accent); }
/* A step holding what publishing refused (#439): a steady dot in the
   tab's top corner, never flashing. The refusal edge's red, which holds
   3:1 on the tab's field ground in every look (SiteThemeContrastTest).
   A border rather than a fill, so forced colours still draw it. */
.v-step { position: relative; }
.v-step-mark {
  position: absolute; inset-block-start: .3rem; inset-inline-end: .3rem;
  inline-size: 0; block-size: 0; border: .25rem solid var(--v-danger-strong); border-radius: 50%;
}
/* The fourth tab while the draft cannot be published (#50): there, greyed,
   not a link. */
.v-step--off { opacity: .45; cursor: not-allowed; }
/* What keeps it closed, under the tabs, each item a link to its step. */
.v-steps-hint { margin: -1rem 0 1.25rem; font-size: .85rem; color: var(--v-warn); display: flex; flex-wrap: wrap; gap: .35rem; }
.v-steps-hint a { color: inherit; font-weight: 600; }
/* What on the card is over today's limits (#340): the warning's own colours,
   a heading the size of the text, and one row a field, each a link. */
.v-over-limits-heading { margin: 0 0 .3rem; font-size: 1rem; }
.v-over-limits p { margin: 0; }
.v-over-limits-rows { margin: .4rem 0 0; padding-inline-start: 1.2rem; }
.v-over-limits-rows a { color: inherit; font-weight: 600; }
/* One line a label, one width a tab, room on both sides at every screen
   (#68 round 5, Adam's decision after his look at the row).

   The icon sits over the word rather than before it, which is what makes
   the rest possible: measured with the icons in, the editor pane gives the
   row 422px at 1400px, a share of 100.7px a tab, and "מדיה חברתית"
   beside its icon wants 117.6px of it. Over the word it wants 96.8px and
   fits, with .5rem of air on either side of it. So the whole row is the
   phone's own layout now, at every width — one look, not two.

   The type size is what the share allows, and the share follows the pane:
   422px above the editor's 64rem breakpoint, 368 to 382px below it where
   the form has the screen to itself, and 247px on a 360px phone inside the
   card's own padding. Hence .9rem, .8rem and .7rem, each the largest that
   holds one line with its room at the narrowest width of its zone. The
   English labels are a word each for the same reason: "Contact details"
   over two words wants 116.9px, more than any zone has.

   Chosen against wrapping a two-word label (Adam: every word on one line),
   against a column that takes its own content (tabs of five widths, and the
   English row ran past its pane), and against `min-inline-size: 0`, which
   is what let "מדיה חברתית" sit over its own border. */
.v-step { white-space: nowrap; text-align: center; line-height: 1.2; }
/* Below the editor's own breakpoint the form has the screen to itself and
   the row is 368 to 382px wide — a share of 89px a tab, where .9rem does
   not hold one line. */
@media (max-width: 63.99rem) {
  .v-steps { gap: .25rem; }
  .v-step { font-size: .8rem; }
}
/* On a phone the seven tabs are one row inside the card that scrolls
   sideways, the current tab brought into view by the step-strip controller
   (#302; Adam's phone hand test of #300, 2026-09-29, against two contained
   rows and against icons only on the phone).

   Until then the row was the four-column grid above reaching 2.5rem (40px)
   past the card on either side, against the card's own 1.75rem (28px) of
   padding: seven tabs in four columns wrapped four over three, and the
   12px the row reached past the card's border left that border running
   behind the tabs. Both go: the 2.5rem reach drops to the -4px the focus
   ring below asks for, which keeps the row inside the card's padding, and
   a flex row that overflows carries the tabs it cannot show.

   One width a tab still (they are one width at every screen), so the width
   is a basis rather than the content's: at the .8rem the zone above already
   sets, the widest label, "מדיה חברתית", measures 70px over its icon, and
   6rem (96px) leaves 13px of air on either side of it — over the .5rem the
   row keeps everywhere else, and room for a longer translation. The row no
   longer divides the phone's 247px seven ways, which is what forced .7rem
   before this.

   The scrollbar is hidden: it would draw over the tabs in the 1.5rem under
   the row, and a row that stops mid-tab is its own cue. The 4px of padding
   is the focus ring's: `overflow-y: hidden` clips whatever is drawn
   outside the row, and the ring stands 2px off the tab it is on. Every
   side of that padding comes back off as a margin — -4px on the inline
   sides and on the top, and 1.5rem - 4px under — so the row sits exactly
   where it did. */
@media (max-width: 30rem) {
  /* The pane is a grid item of the editor's shell, and a grid item's floor
     is its own min-content: without this the card grew to the row's whole
     780px, carrying the row past the screen instead of scrolling it. */
  .v-shell--editor > .v-pane { min-inline-size: 0; }
  .v-steps {
    display: flex;
    overflow-x: auto; overflow-y: hidden;
    scrollbar-width: none;
    padding: 4px; margin-block: -4px 1.25rem; margin-inline: -4px;
    scroll-padding-inline: calc(var(--v-steps-fade) + 4px);
  }
  .v-steps::-webkit-scrollbar { display: none; }
  .v-step { flex: 0 0 6rem; }
}
/* The fade is the row's scroll cue (#343, Adam's hand test, 2026-10-01,
   against the mid-tab cut alone, which he missed, and against a scroll bar
   or arrows): the edge with more tabs behind it goes out, on the side
   those tabs are in — the start is the right in Hebrew, the left in
   English. scroll-fade marks the edge, and only while the row overflows,
   so a row that fits is never masked whatever the screen. The tab the
   keyboard moves to stops clear of the fade, ring and all: the row's
   scroll-padding above is the fade plus the ring's 4px. */
.v-steps { --v-steps-fade: 2rem; }
.v-steps[data-more="end"] { mask-image: linear-gradient(to right, #000 calc(100% - var(--v-steps-fade)), transparent); }
.v-steps[data-more="start"] { mask-image: linear-gradient(to left, #000 calc(100% - var(--v-steps-fade)), transparent); }
[dir="rtl"] .v-steps[data-more="end"] { mask-image: linear-gradient(to left, #000 calc(100% - var(--v-steps-fade)), transparent); }
[dir="rtl"] .v-steps[data-more="start"] { mask-image: linear-gradient(to right, #000 calc(100% - var(--v-steps-fade)), transparent); }
.v-steps[data-more="both"] {
  mask-image: linear-gradient(to right, transparent, #000 var(--v-steps-fade), #000 calc(100% - var(--v-steps-fade)), transparent);
}
/* Finish is one tab among the others, the same size, in the row with
   them on every screen (Adam's hand test, 2026-09-17, #177), against the
   full-width row of its own it had from the #152 hand test (2026-09-14):
   on a phone that row read as a bar at the bottom, not a tab. Only the
   pill shape and the green tell it apart. */
.v-step--finish { border-radius: 999px; }
/* Green with white text while it can be pressed: the way to the press
   (Adam, 2026-09-09). Greyed, it keeps the plain box look. */
.v-step--finish:not(.v-step--off) { background: var(--v-go); border-color: var(--v-go-line); color: var(--v-on-go); }
.v-step--finish.v-step--current { border-color: var(--v-ok); }
/* Where the tabs sit four over four, Finish takes the bottom row's far
   end, under Social, and the slot between Design and Finish holds a dashed
   map path that ends at Finish's flag (#352, Adam's hand test, 2026-10-01,
   against an eighth tab and against leaving the gap): one loop over the
   road and one under it (his look rounds). Grid placement only: the
   markup, the tab order and the step order are unchanged. Static, in the
   look's muted ink; under forced colours currentColor is the system's
   text colour, so the path stays drawn. Drawn left to right, Design to
   Finish, and mirrored where the row runs right to left. The drawing is
   pinned to its cell, so it never sets the row's height. */
.v-steps-path { grid-row: 2; grid-column: 3; position: relative; pointer-events: none; color: var(--v-ink-muted); }
.v-steps-path svg { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; overflow: visible; }
.v-steps-path path { fill: none; stroke: currentColor; stroke-width: 2; stroke-dasharray: 5 4; stroke-linecap: round; vector-effect: non-scaling-stroke; }
[dir="rtl"] .v-steps-path svg { transform: scaleX(-1); }
.v-step--finish { grid-row: 2; grid-column: 4; }
/* An imported card's address step (#462) is the eighth tab: four over
   four fills both rows, so there is no slot for the path, and Finish
   flows after Address in order (review of #462, finding 1). */
.v-steps--eight .v-steps-path { display: none; }
.v-steps--eight .v-step--finish { grid-row: auto; grid-column: auto; }
/* The phone's swiping row has no slot to fill. */
@media (max-width: 30rem) {
  .v-steps-path { display: none; }
}
/* An arrow between each two tabs on the phone's swiping row, pointing to
   the next step (#415, Adam, 2026-10-04): the row read as tabs, not as
   steps in order. Decoration only, aria-hidden and out of the Tab order;
   wider screens keep the map path and draw none. The row's gap goes and
   the arrow's slot stands in for it, so the row grows by 8px a pair, not
   by a whole arrow. Drawn pointing right and mirrored where the row runs
   right to left, as the map path is; the look's muted ink, which holds
   4.5:1 on every look's ground (SiteThemeContrastTest), over the 3:1 a
   graphic needs. */
.v-steps-arrow { display: none; }
@media (max-width: 30rem) {
  .v-steps { gap: 0; }
  .v-steps-arrow { display: flex; flex: 0 0 .75rem; align-items: center; justify-content: center; color: var(--v-ink-muted); pointer-events: none; }
  .v-steps-arrow svg { inline-size: .4rem; block-size: .6rem; overflow: visible; }
  .v-steps-arrow path { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
  [dir="rtl"] .v-steps-arrow svg { transform: scaleX(-1); }
}
/* On a computer the steps leave the box and run down the empty space
   between the side bar and it, on the box's start side, details at the
   top and finish at the bottom (#435, Adam, 2026-10-05). The step the
   realtor is on is filled with the site look's accent, its words the
   accent's own (SiteThemeContrastTest holds that pair, and the muted ink
   on the page, at 4.5:1 in every look); the others are grey words on the
   page that stay links. Finish loses its green here: it is one grey step
   among the others until it is the current one.

   The nav stays where it is in the step frame, so the Tab order, the
   aria-current, the step links and the error dot (#439) are the tabs'
   own. The box is its containing block and it is placed past the box's
   start edge, inside start padding the shell grows by the list's width
   and its gap. 73.25rem is the narrowest window where the side bar, the
   list, the box at its 24rem floor and the widest phone (a layout's card
   at its true width, 477px) sit side by side, the gap before the phone
   down to the list's own 1.5rem and the far padding to .5rem (Adam's
   hand test of #455: a 110% zoom on his window keeps the list); below it
   the box keeps its tabs. */
@media (min-width: 73.25rem) {
  /* Only a shell that holds the steps: the languages page's long form has
     no list to make room for. */
  .v-shell--editor:has(.v-steps) {
    --v-steps-list: 10rem; --v-steps-list-gap: 1.5rem; --v-steps-room: calc(var(--v-steps-list) + var(--v-steps-list-gap));
    --v-preview-gap: var(--v-steps-list-gap); --v-shell-end: .5rem;
  }
  .v-shell--editor > .v-card { position: relative; }
  .v-shell--editor .v-steps {
    position: absolute; inset-block-start: 0; inset-inline-end: calc(100% + var(--v-steps-list-gap));
    inline-size: var(--v-steps-list); margin: 0;
    display: flex; flex-direction: column; gap: .25rem;
  }
  .v-shell--editor .v-steps-path { display: none; }
  .v-shell--editor .v-steps .v-step,
  .v-shell--editor .v-steps .v-step--finish:not(.v-step--off) {
    flex-direction: row; justify-content: flex-start; gap: .6rem;
    padding: .55rem .8rem; font-size: .95rem; text-align: start; white-space: normal;
    color: var(--v-ink-muted); background: transparent; border-color: transparent; border-radius: var(--v-radius);
  }
  .v-shell--editor .v-steps a.v-step:not(.v-step--current):hover { color: var(--v-ink); }
  .v-shell--editor .v-steps .v-step.v-step--current { color: var(--v-on-accent); background: var(--v-accent); border-color: var(--v-accent); }
  /* The error dot's red is held against the field ground, not the accent:
     on the filled step a ring in the accent's own words keeps it apart. */
  .v-shell--editor .v-steps .v-step--current .v-step-mark { box-shadow: 0 0 0 2px var(--v-on-accent); }
  .v-shell--editor .v-steps-hint { margin-block-start: 0; }
}
/* The list stays in view while a long step scrolls (Adam's hand test of
   #455), pinned a fifth of the way down, so its middle lands a little
   above the screen's. Sticky needs the list in the flow: it floats to
   the box's start side and a negative margin carries it out past the
   box's padding, border and the gap, where it takes no room from the
   form. A window too short to hold the whole list below that line keeps
   it at the box's top instead, never cut off. */
@media (min-width: 73.25rem) and (min-height: 36rem) {
  .v-shell--editor .v-steps {
    position: sticky; inset-block-start: 20vh; inset-inline-end: auto; float: inline-start;
    margin-inline-start: calc(-1 * (var(--v-steps-list) + var(--v-steps-list-gap) + 1.75rem + 1px));
  }
}

/* The two sides of a changed picture in the change list (1.4b): the one
   on the card and the one about to replace it, small, side by side. */
.v-dialog-pictures { display: flex; align-items: center; gap: 1rem; margin-block: .6rem 1rem; }
.v-dialog-picture { display: flex; flex-direction: column; gap: .35rem; align-items: flex-start; }
.v-dialog-picture img { max-block-size: 6.75rem; max-inline-size: 9rem; border-radius: 8px; }
/* The arrow reads with the page: it points at the new picture, which sits
   at the reading end. Font Awesome draws it pointing left, which is right
   in Hebrew and back to front in English. */
.v-dialog-arrow { color: var(--v-ink-muted); font-size: 1.1rem; }
[dir="ltr"] .v-dialog-arrow { transform: scaleX(-1); }

/* The images step (stage 3 step 2). A picture box is its frame, the
   picture inside it and the two presses under it. The frame keeps its
   height whether or not there is a picture, so the step does not jump
   when one is picked. */
.v-image-field { margin-block-end: 1.5rem; }
/* Each picture's hint in the step intro's grey (Adam, 2026-10-03): guidance
   under the heading, not part of it. --v-ink-muted on the page ground is a
   pair every site palette already holds for .v-note. */
.v-image-field > .v-hint { color: var(--v-ink-muted); }
/* The agency's name under its logo's presses (#448), spaced off them. */
.v-field--in-image { margin-block-start: 1rem; }
/* The ground behind the picture, and behind the line that stands in for
   one while there is none (Adam's hand test, 2026-09-19). The frame is a
   place a picture goes, so it reads as a place before one is chosen. */
.v-image-frame {
  display: flex; align-items: center; justify-content: center;
  min-block-size: 9rem; padding: .75rem; margin-block-start: .5rem;
  background: var(--v-field);
  border: 1px dashed var(--v-line); border-radius: var(--v-radius);
}
.v-image-shown { max-block-size: 12rem; max-inline-size: 100%; border-radius: var(--v-radius); }
.v-image-empty { color: var(--v-ink-muted); font-size: .9rem; }
/* The file input itself is never shown: its own button says "Choose file"
   in the browser's language, which on a Hebrew card is the wrong word in
   the wrong direction. The label around it is the press. */
.v-file { position: absolute; inline-size: 1px; block-size: 1px; opacity: 0; pointer-events: none; }
label.v-btn { cursor: pointer; }
/* The file box takes the focus but cannot be seen; its press wears the ring. */
label.v-btn:has(> .v-file:focus-visible) { outline: 2px solid var(--v-accent); outline-offset: 2px; }
.v-actions--image { justify-content: flex-start; gap: .5rem; }
/* Dropping a picture on its box (#430). On a computer the frame is drawn
   as the place a picture is dropped: a dashed edge in the editor field's
   frame colour, which holds 3:1 against the page, the panel and the field
   in every look, and an empty frame says to drag a picture there. The
   edge is an SVG rectangle over the frame rather than a border, because a
   dashed border leaves the length of its dashes to the browser and Adam
   asked for long ones (round 3). A phone, whose one pointer is a finger
   that cannot hover, sees the step as it was: the faint line and "no
   picture". A laptop with a touch screen
   still has a mouse or a pad as its first pointer, so it counts as a
   computer. While a file is over the box the frame is ringed in the
   look's accent, solid and outside the dashed edge, so the box still
   changes when the file arrives. */
.v-image-frame { position: relative; border: 0; }
.v-image-edge { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; overflow: visible; pointer-events: none; }
.v-image-edge rect {
  x: 1.5px; y: 1.5px; width: calc(100% - 3px); height: calc(100% - 3px); rx: var(--v-radius);
  fill: none; stroke: var(--v-frame); stroke-width: 3px; stroke-dasharray: 12px 8px;
}
@media (hover: none) and (pointer: coarse) {
  .v-image-frame { border: 1px dashed var(--v-line); }
  .v-image-edge { display: none; }
  .v-image-none {
    position: static; inline-size: auto; block-size: auto; margin: 0;
    overflow: visible; clip-path: none; white-space: normal;
  }
  .v-image-drop-here { display: none; }
}
.v-image-field--drop .v-image-frame { outline: 3px solid var(--v-accent); outline-offset: 2px; }
/* A refused picture, by the server (field-error marks the file input) or
   by the pick's own check (its line has words): the frame's edge goes red,
   as a refused box's border does (#444 sweep). */
.v-image-field:has(.v-file.is-refused, [data-image-field-target=message]:not(:empty)) .v-image-edge rect { stroke: var(--v-danger-strong); }
.v-image-field:has(.v-file.is-refused, [data-image-field-target=message]:not(:empty)) .v-image-frame { border-color: var(--v-danger-strong); }
/* The crop (step 2b). Picking a picture opens this over the whole screen:
   the page blurred behind it, the picture as big as the screen allows and
   one press under it (Adam, 2026-09-11). */
.v-image-field [hidden] { display: none; }
.v-crop {
  inline-size: min(96vw, 72rem); max-inline-size: none; padding: 1rem; border: 1px solid var(--v-line);
  border-radius: var(--v-radius); background: var(--v-surface); color: var(--v-ink); box-shadow: var(--v-shadow);
}
.v-crop::backdrop { background: rgba(0, 0, 0, .65); backdrop-filter: blur(6px); }
/* Cropper measures the picture it is given, so the ceiling is on the
   picture and the box follows it. */
/* Three fifths the box, two fifths the card's own shape, the two centred
   on each other (Adam, 2026-09-11). On a phone the shape goes above the
   box, where a thumb is not covering it. */
/* The bases are widths, not shares: a share of a phone's screen is still
   a share, so both panes shrank to fit beside each other and the line
   never wrapped — the circle beside the box was drawn as a tall oval on a
   phone, which is not the shape the card draws (Adam's hand test,
   2026-09-11). Under about 38rem the two no longer fit on one line and
   wrap-reverse puts the shape on top. */
.v-crop-panes { display: flex; flex-wrap: wrap-reverse; align-items: center; gap: 1.5rem; }
.v-crop-box { flex: 1 1 20rem; display: flex; justify-content: center; min-inline-size: 0; }
.v-crop-preview { flex: 1 1 16rem; margin: 0; display: flex; flex-direction: column; align-items: center; gap: .5rem; }
.v-crop-preview .v-hint { margin: 0; text-align: center; }
/* The shape keeps its own proportions whatever width is left for it:
   the height follows the width rather than standing still. */
.v-crop-preview-shape { max-inline-size: 100%; block-size: auto; border: 2px solid var(--v-line); background: var(--v-page); }
.v-crop-preview-shape--photo { inline-size: 16rem; aspect-ratio: 1; border-radius: 50%; }
/* The crop preview wears the shape the photo is set to (#227), so what the
   realtor composes is what the card shows. It follows the toggle as it is
   flipped, before anything is saved: the toggle's radios and this dialog
   sit in one form, so the stylesheet can read the pick and no script has
   to. The crop itself is square either way — the shape is a mask over it —
   so flipping never invalidates a crop already made. */
.v-image-field:has(input[name="nadlan_card[photo_shape]"][value="square"]:checked) .v-crop-preview-shape--photo { border-radius: 0; }
/* The logo's preview follows its own toggle the same way (#447): square
   unless the toggle says round. */
.v-crop-preview-shape--logo { inline-size: 16rem; aspect-ratio: 8 / 3; border-radius: 0; }
.v-image-field:has(input[name="nadlan_card[logo_shape]"][value="round"]:checked) .v-crop-preview-shape--logo { border-radius: var(--v-radius); }
.v-crop-preview-shape--property_photo { inline-size: 16rem; aspect-ratio: 16 / 9; border-radius: var(--v-radius); }
.v-crop-box img { display: block; max-inline-size: 100%; max-block-size: 66vh; }
/* The frame takes focus of its own (#219), and its ring has to be seen
   against whatever photo is under it: the panel's own ground laid outside
   the accent line, so the two together read on a dark photo and a light
   one alike. */
.cropper-crop-box:focus-visible { outline: 3px solid var(--v-accent); outline-offset: 0; box-shadow: 0 0 0 6px var(--v-surface); }
/* Stacked, the screen holds both plus the three presses only if each one
   gives up some height. */
@media (max-width: 38rem) {
  .v-crop-preview-shape--photo { inline-size: 9rem; }
  .v-crop-preview-shape--logo,
  .v-crop-preview-shape--property_photo { inline-size: 12rem; }
  .v-crop-box img { max-block-size: 42vh; }
}
.v-crop-hint { margin-block: .6rem 0; }
/* The presses start on the reading side — the right in Hebrew (Adam,
   2026-09-11). flex-start follows the page's direction; flex-end put them
   on the left. */
.v-actions--crop { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: flex-start; margin-block-start: .8rem; }

/* The editor with its preview (step 1.3). One column on a phone, where
   the two panes are tabs; two columns from 64rem, form on the reading
   side and the phone-shaped frame beside it, staying put while the form
   scrolls. */
.v-shell--editor { display: grid; gap: 1rem; }
.v-panes { display: flex; gap: .4rem; margin: 0; }
/* Flex since #68, so the tab's icon sits beside its word rather than on a
   line of its own. */
.v-pane-tab {
  flex: 1 1 0; display: flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .55rem .4rem; font: inherit; font-size: .9rem; cursor: pointer;
  color: var(--v-ink-muted); background: var(--v-field);
  border: 1px solid var(--v-line); border-radius: var(--v-radius);
}
.v-pane-tab.is-current { color: var(--v-ink); border-color: var(--v-accent); }
.v-preview { display: grid; justify-items: center; gap: .75rem; }
/* The heading over the phone (#187, Adam, 2026-09-19). Twice the size it
   first shipped at and in the accent rather than the muted grey, because
   grey and small read as a caption on the phone rather than as the name of
   what the realtor is looking at. Centred with the phone under it, and
   allowed to wrap on a narrow screen rather than widen the pane. */
.v-preview-label {
  margin: 0; font-size: 1.8rem; font-weight: 600; line-height: 1.2;
  color: var(--v-accent); text-align: center; text-wrap: balance;
}
/* Sized by height as well as width: the pane is pinned only while it fits
   the window, so the phone takes what is left under the pill once the
   shell's padding above and below (3rem each), the pill and the gap are
   out — and the card scrolls inside it (#50; Adam's desktop round,
   2026-09-09: with the QR press under it the pane was taller than the
   window on a short step and simply scrolled with the page). */
.v-phone {
  /* 12.5rem, not the 9.5rem this shipped with: the heading over the phone
     (#187, Adam, 2026-09-19) is 1.8rem on a 1.2 line plus its own .75rem
     gap, and without that in the budget the pane grew taller than the
     window — which is the one thing that stops `position: sticky` sticking,
     so the phone scrolled away with the form (Adam's hand test). The
     heading is one line at this pane's 22rem, and the cap is off on a
     phone, where the pane is the whole tab. */
  inline-size: min(100%, 22rem); max-block-size: calc(100vh - 12.5rem); aspect-ratio: 9 / 18; background: #000;
  border: 8px solid var(--v-line); border-radius: 2.2rem; overflow: hidden;
}
.v-phone-screen { display: block; inline-size: 100%; block-size: 100%; border: 0; background: var(--v-page); }
.v-preview-qr { inline-size: 7rem; padding: .35rem; background: #fff; border-radius: 8px; margin-block-start: .5rem; }
.v-preview-qr svg { display: block; inline-size: 100%; block-size: auto; }

/* The fourth screen: publish and unpublish (#50). The green press is the
   biggest on the page: the screen is the "are you sure". */
/* The design step (#186): a picker's section, its pop-up, and the strip
   that stands for a palette. Every pop-up on the step wears these classes —
   the colours and the font (Adam, 2026-09-19, "exactly the same format") —
   so nothing here names a colour: a palette's own colours are written inline from its tokens. */
/* The section is a field box (#203), so the box supplies the padding and
   the section supplies only the layout inside it. */
.v-design-section { display: grid; gap: .5rem; justify-items: start; }
.v-design-heading { margin: 0; font-size: 1.1rem; }
.v-design-current { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin: .2rem 0 .4rem; }
.v-design-current-label { color: var(--v-ink-muted); }
/* Says the palette beside it was not picked, so it reads quieter than the
   name it qualifies. */
.v-design-current-note { color: var(--v-ink-muted); font-size: .85rem; }
.v-design-current-name { font-weight: 600; }

/* Four bands in a row, the palette's ground, card, accent and ink. The
   frame round them is the site's, not the palette's: a strip of four pale
   colours on a white page needs an edge to be a strip at all. */
.v-palette-swatch { display: inline-flex; overflow: hidden; border: 1px solid var(--v-frame); border-radius: 6px; }
.v-palette-band { inline-size: 1.25rem; block-size: 1.5rem; }

/* A layout drawn small (#323): a card in miniature, the photo, the name, a
   line and the presses set out as that layout sets them. Bars in the
   editor's muted ink and the presses in its accent, since a layout picks
   no colour; decorative, the name beside it says which one it is. */
.v-layout-swatch {
  display: grid; grid-template-columns: 1fr 1fr; align-content: start; gap: 3px;
  inline-size: 2.75rem; block-size: 4rem; padding: 5px; border: 1px solid var(--v-frame); border-radius: 6px;
}
.v-layout-swatch > * { grid-column: 1 / -1; border-radius: 1px; background: var(--v-ink-muted); }
.v-layout-swatch-photo { justify-self: center; inline-size: 12px; block-size: 12px; border-radius: 50%; }
.v-layout-swatch-name { justify-self: center; inline-size: 70%; block-size: 4px; }
.v-layout-swatch-line { justify-self: center; inline-size: 45%; block-size: 2px; opacity: .6; }
.v-layout-swatch .v-layout-swatch-press { block-size: 5px; background: var(--v-accent); }
.v-layout-swatch .v-layout-swatch-press--half { grid-column: auto; }
/* Classic: today's card — centred, the presses a row of equal rounds. */
.v-layout-swatch[data-layout="classic"] { border-radius: 8px; grid-template-columns: repeat(3, 1fr); }
.v-layout-swatch[data-layout="classic"] .v-layout-swatch-press { grid-column: auto; justify-self: center; inline-size: 5px; border-radius: 50%; }
/* Quiet: square, the agency over a hairline, the portrait at the far side,
   the name read from the start. */
.v-layout-swatch[data-layout="quiet"] { border-radius: 0; }
.v-layout-swatch[data-layout="quiet"] .v-layout-swatch-line { order: -1; justify-self: stretch; inline-size: auto; }
.v-layout-swatch[data-layout="quiet"] .v-layout-swatch-photo { justify-self: end; inline-size: 9px; block-size: 9px; }
.v-layout-swatch[data-layout="quiet"] .v-layout-swatch-name { justify-self: start; }
/* Horizon: the agency over a band of the accent where the property photo
   goes, the portrait over its edge, WhatsApp beside two squares. */
.v-layout-swatch[data-layout="horizon"] { grid-template-columns: 2fr 1fr 1fr; }
.v-layout-swatch[data-layout="horizon"] .v-layout-swatch-line { order: -2; justify-self: start; }
.v-layout-swatch[data-layout="horizon"]::before { content: ""; order: -1; grid-column: 1 / -1; block-size: 14px; margin-inline: -5px; background: var(--v-accent); opacity: .55; }
.v-layout-swatch[data-layout="horizon"] .v-layout-swatch-photo { position: relative; justify-self: start; inline-size: 10px; block-size: 10px; margin-block-start: -8px; }
.v-layout-swatch[data-layout="horizon"] .v-layout-swatch-name { justify-self: start; }
.v-layout-swatch[data-layout="horizon"] .v-layout-swatch-press { grid-column: auto; }
/* Close: an arched card, the portrait centred in an arch of its own. */
.v-layout-swatch[data-layout="close"] { border-radius: 1.4rem 1.4rem 4px 4px; padding-block-start: 7px; }
.v-layout-swatch[data-layout="close"] .v-layout-swatch-photo { box-shadow: 0 0 0 2px var(--v-frame); }
.v-layout-swatch[data-layout="close"] .v-layout-swatch-press { border-radius: 3px; }
/* Story: square, the portrait and a large name read from the start, the
   agency's line under them, the pair of presses over the save line. */
.v-layout-swatch[data-layout="story"] { border-radius: 0; }
.v-layout-swatch[data-layout="story"] .v-layout-swatch-line { justify-self: stretch; inline-size: auto; }
.v-layout-swatch[data-layout="story"] .v-layout-swatch-photo { justify-self: start; inline-size: 8px; block-size: 8px; }
.v-layout-swatch[data-layout="story"] .v-layout-swatch-name { justify-self: start; inline-size: 85%; block-size: 5px; }
.v-layout-swatch[data-layout="story"] .v-layout-swatch-press { border-radius: 0; }
.v-layout-swatch[data-layout="story"] .v-layout-swatch-press:not(.v-layout-swatch-press--half) { order: 1; }
/* Grid: tiles — the portrait beside the name, the WhatsApp press a tall
   tile beside two short ones. */
.v-layout-swatch[data-layout="grid"] { border-radius: 0; }
.v-layout-swatch[data-layout="grid"] .v-layout-swatch-photo { grid-column: 1; justify-self: start; inline-size: 9px; block-size: 9px; }
.v-layout-swatch[data-layout="grid"] .v-layout-swatch-name { grid-column: 2; align-self: center; inline-size: 100%; }
.v-layout-swatch[data-layout="grid"] .v-layout-swatch-press { border-radius: 2px; }
.v-layout-swatch[data-layout="grid"] .v-layout-swatch-press:not(.v-layout-swatch-press--half) { grid-column: 1; grid-row: span 2; block-size: auto; }
/* Signature: a double frame, the portrait ringed, the name in the accent. */
.v-layout-swatch[data-layout="signature"] { border-radius: 0; outline: 1px solid var(--v-frame); outline-offset: -4px; }
.v-layout-swatch[data-layout="signature"] .v-layout-swatch-photo { outline: 1px solid var(--v-accent); outline-offset: 1px; }
.v-layout-swatch[data-layout="signature"] .v-layout-swatch-name { background: var(--v-accent); }
.v-layout-swatch[data-layout="signature"] .v-layout-swatch-press { border-radius: 0; }

/* Two panes, each its own screen (Adam, 2026-09-19): the choices and their
   presses on one, the card under the editor's own heading on the other.
   Neither is stretched — a row of choices two-thirds empty was the pop-up
   at its widest, and it read as a table rather than as a list of looks. So
   the pop-up takes the width its two panes need and no more. */
/* fit-content, not auto: a modal dialog is positioned against the whole
   window, so `auto` filled it and left the two panes swimming in it (Adam,
   2026-09-19). The pop-up wraps its panes, and the padding below is the
   room round them. */
.v-dialog.v-look { inline-size: fit-content; max-inline-size: 96vw; padding: 1.75rem 2rem; }
/* The line under the layout pop-up's title (#446), close under it and
   apart from the tabs or panes below. A phone's own line, when the picker
   has one, stands in for it under the breakpoint (see the phone block). */
.v-look .v-look-hints { margin-block: -.2rem 1rem; color: var(--v-ink-muted); }
.v-look .v-look-hint { margin: 0; }
.v-look .v-look-hint--phone { display: none; }
.v-look-panes { display: grid; grid-template-columns: auto auto; gap: 2.5rem; align-items: start; justify-content: center; }
/* Centred against the phone, which is the taller pane and sets the row's
   height (Adam, 2026-09-19): six choices hanging from the top of a
   44rem-tall row read as an afterthought beside the card. */
.v-look-choices { display: grid; gap: 1.25rem; align-self: center; }
.v-look-set { display: grid; gap: .6rem; border: 0; padding: 0; margin: 0; max-block-size: calc(100vh - 16rem); overflow-y: auto; }
/* As wide as a choice is, with room around it: the swatch and the name set
   the width, and the padding is what keeps the row from being crowded. */
.v-look-choice {
  display: flex; align-items: center; gap: 1.1rem;
  padding: var(--v-look-pad) 1.4rem; border: 1px solid var(--v-line); border-radius: 10px; cursor: pointer;
}
/* The picked row is marked by more than its radio: the radio is small, and
   the row is what the eye is reading. */
.v-look-choice:has(:checked) { border-color: var(--v-accent); background: var(--v-tray); }
.v-look-choice:has(:focus-visible) { outline: 2px solid var(--v-accent); outline-offset: 2px; }
/* The names are as long as they are — זית is three letters and קטיפה five —
   so the column they sit in is as wide as the longest of them and every
   strip beside them starts on the same line. */
.v-look-name { font-weight: 600; min-inline-size: 4rem; }
/* The colours as two columns (#322): filled down, so the first half is the
   first column — the right-hand one in Hebrew. Six high by default; the
   palettes' and the looks' sixteen (#422) set eight, half their list.
   The side bar's looks are the same two columns (Adam,
   2026-10-01), so the height is the one thing a list sets for itself; the
   fonts' twelve take the default six too, and the layouts' seven stand four
   high in columns a phone undoes (#358). */
.v-look-set--paired, .v-look-set--columns { grid-template-rows: repeat(var(--v-look-rows, 6), auto); grid-auto-flow: column; column-gap: 1rem; }
/* Room inside the list for a focus ring on every side (Adam, 2026-10-01):
   the list scrolls, so it clips what runs past its own box, and a choice
   at its edge lost that side of its ring — 2px of outline and 2px of
   offset — at every size and in every list. */
.v-look-set { --v-look-pad: .7rem; --v-look-clear: 4px; padding: 4px; }
/* The choice the keyboard moves to stops clear of the list's edge, ring
   and all, and on a phone clear of the fade (reviewer-342, round 7). The
   arrow keys focus the radio, and the browser scrolls the radio — not its
   row — into view, so the margin is the radio's: the clearance, plus the
   distance from the radio to its row's edge — the row's border, its
   padding, and half of what the name's line leaves beside the radio's
   13px and its 3px top margin (both the browser's own, written down here
   so the sum is exact). The list is a fieldset, which ignores its own
   scroll-padding, so the margin cannot sit on the list either. */
.v-look-radio {
  block-size: 13px; margin-block: 3px 0;
  --v-look-inset: calc(1px + var(--v-look-pad) + (1rem * var(--v-line-height) - 16px) / 2);
  scroll-margin-block: calc(var(--v-look-clear) + var(--v-look-inset) + 3px) calc(var(--v-look-clear) + var(--v-look-inset));
}
/* The fade marks the edge with more choices behind it, beside the
   scroll bar the layouts have (Adam on the deployed site: the fade alone
   did not read as a list that scrolls); a choice reached by the keyboard
   stops clear of it (the radio's scroll-margin). scroll-fade marks which
   edge. On a wide screen too (review of #422): the sixteen stand eight
   high and scroll inside a laptop's short window. */
.v-look-set--paired { --v-look-fade: 2rem; --v-look-clear: calc(var(--v-look-fade) + 4px); }
.v-look-set--paired[data-more="below"] { mask-image: linear-gradient(to bottom, #000 calc(100% - var(--v-look-fade)), transparent); }
.v-look-set--paired[data-more="above"] { mask-image: linear-gradient(to top, #000 calc(100% - var(--v-look-fade)), transparent); }
.v-look-set--paired[data-more="both"] {
  mask-image: linear-gradient(to bottom, transparent, #000 var(--v-look-fade), #000 calc(100% - var(--v-look-fade)), transparent);
}
/* The presses answer for the choices, so they sit under them (Adam,
   2026-09-19), not under the card. */
/* They stand at the pop-up's foot while what is above them scrolls (the
   review of #446): the line under the title told the realtor to press
   "שמירה" and pushed it off a laptop's screen, and on a phone the corners
   under the list had it below the fold already. The negative margin and
   the padding equal to it lay the press's ground over the pop-up's own
   bottom padding, so a stuck press keeps that room under it and the list
   scrolls behind, not under, it. The inset is minus that padding too: the
   browser measures a stuck edge from inside the pop-up's padding, so at 0
   the press rode up over a list that had not scrolled at all. */
.v-look .v-actions--dialog {
  position: sticky; inset-block-end: -1.75rem; z-index: 1; justify-content: center;
  margin: 0 0 -1.75rem; padding-block: .75rem 1.75rem; background: var(--v-surface);
}

/* The card's own pane: the heading the editor's phone carries, and the
   phone under it. */
.v-look-preview { display: grid; justify-items: center; gap: .75rem; }
.v-look-preview .v-preview-label { font-size: 1.2rem; }

/* The same phone as the one beside the form, at the same size and in the
   same plain frame (Adam, 2026-09-19: "the same relative size as the editor
   preview cause all the elements look weird on it now" — the card page is
   responsive, so a narrower phone is not the same card smaller, it is a
   different layout). The frame is furniture, not part of the look (Adam,
   2026-09-19, correcting a bezel that took the palette's accent): what the
   palette paints is inside it — the card and the ground it stands on,
   which is the card's own --v-page and is what a visitor sees. */
.v-look-phone {
  inline-size: min(100%, 22rem); aspect-ratio: 9 / 18; max-block-size: calc(100vh - 12rem); background: #000;
  border: 8px solid var(--v-line); border-radius: 2.2rem; overflow: hidden;
}
.v-look-screen { display: block; inline-size: 100%; block-size: 100%; border: 0; background: var(--v-page); }

/* The page behind goes out of focus, so the pop-up and the card in it are
   the only things in view. The scrim's own colour is the dialogs' (below);
   the blur is what this adds. */
.v-look::backdrop { backdrop-filter: blur(6px); }

/* The shape toggles (#227): two choices side by side on the step itself,
   no pop-up. The same rules serve the card's edges on the design step and
   the photo's shape under the photo. */
/* Inside another box — the photo's — the toggle is a line in it rather
   than a frame of its own: a rule above it for the step down, and the
   room the step's sections get between them. */
.v-shape-block { display: grid; gap: .5rem; justify-items: start; margin-block-start: 1rem; padding-block-start: 1rem; border-block-start: 1px solid var(--v-line); }
.v-shape-block .v-hint { margin: 0; }
.v-shape-set { display: flex; flex-wrap: wrap; gap: .75rem; border: 0; padding: 0; margin: 0; }
.v-shape-choice {
  display: flex; align-items: center; gap: .7rem;
  padding: .7rem 1.1rem; border: 1px solid var(--v-line); border-radius: 10px; cursor: pointer;
}
.v-shape-choice:has(:checked) { border-color: var(--v-accent); background: var(--v-tray); }
.v-shape-choice:has(:focus-visible) { outline: 2px solid var(--v-accent); outline-offset: 2px; }
.v-shape-name { font-weight: 600; }
/* The shape itself, drawn at the corner it names. A corner is quicker to
   see than to read, and the two words differ by one letter in Hebrew. */
.v-shape-swatch {
  inline-size: 1.6rem; block-size: 1.6rem;
  border: 2px solid var(--v-ink-muted); background: var(--v-field);
}
.v-shape-swatch--round { border-radius: 8px; }
.v-shape-swatch--sharp { border-radius: 0; }
.v-shape-swatch--circle { border-radius: 50%; }
.v-shape-swatch--square { border-radius: 0; }

/* The pop-up's tabs are the phone's alone: a wide screen has both panes
   side by side and nothing to switch. */
.v-look-tabs { display: none; }

/* On a phone the two panes are two tabs (#227), the editor's own form and
   phone in miniature (Adam, 2026-09-21: "on phone view how about we do like
   the editor where you can switch between preview and editor with a press of
   a tab"). It replaces #221's no card at all, which was Adam's ruling of the
   same day against the two panes stacked: the card squeezed under the list
   read as a broken card. A tab gives it the pop-up's width instead, and the
   choices keep theirs. The card on its tab is the editor's phone tab over
   again — no bezel, full width, tall enough to scroll inside the pop-up.

   The switching classes are read here only: on a wide screen `is-off`
   hides nothing, so a phone turned on its side is back over the breakpoint
   with both panes standing. */
@media (max-width: 45rem) {
  .v-look-tabs { display: flex; }
  .v-look .v-look-hint--wide { display: none; }
  .v-look .v-look-hint--phone { display: block; }
  .v-look-panes { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .v-look-pane.is-off { display: none; }
  .v-look-phone { inline-size: 100%; max-block-size: none; aspect-ratio: auto; border: 0; border-radius: 0; background: none; }
  /* 100dvh, and a floor under both: a 360px phone turned sideways is 360px
     tall and still under this breakpoint, where a bare subtraction left the
     list about two choices high and forced a 20rem frame into it (the
     stranger's pass, 2026-09-21). */
  .v-look-screen { block-size: max(12rem, calc(100dvh - 18rem)); }
  .v-look-set { max-block-size: max(9rem, calc(100dvh - 19rem)); }
  .v-look-set { --v-look-pad: .6rem; }
  /* The layouts' columns are a wide screen's; a phone keeps its one. */
  .v-look-set--columns { grid-template-rows: none; grid-auto-flow: row; }
  .v-look-choice { padding: var(--v-look-pad) 1rem; }
  /* One column on a phone: a row is its radio, its name and a 5rem strip,
     and two of them do not fit side by side in a 360px screen's pop-up.
     Five rows high and no more (Adam, 2026-10-01), counted from a row's
     own height — its name's line, the padding above and its borders —
     rather than guessed from the screen; the screen's cap still holds on
     a phone turned sideways; the 8px is the list's own 4px of padding
     above and below, the focus ring's room. */
  .v-look-set--paired {
    --v-look-row: calc(1rem * var(--v-line-height) + 2 * var(--v-look-pad) + 2px);
    grid-template-rows: none; grid-auto-flow: row; grid-auto-rows: var(--v-look-row);
    max-block-size: min(calc(5 * var(--v-look-row) + 4 * .6rem + 8px), max(9rem, calc(100dvh - 19rem)));
  }
  /* Air between the list and the presses: the list's last row touched
     them. */
  .v-look:has(.v-look-set--paired) .v-actions--dialog { margin-block-start: 1.25rem; }
}

.v-finish { display: grid; justify-items: center; gap: .6rem; padding-block: 1rem; text-align: center; }
.v-finish .v-btn { margin-block-start: .4rem; }
/* The screen's press and the way back on one line, centred, air between
   them and from the walls (Adam, 2026-09-09). */
.v-finish-actions { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 1.5rem; padding-inline: 1rem; margin-block-start: 3.75rem; }
.v-finish-actions--under { margin-block-start: 1.5rem; }
/* Finish's back sits on one row with the screen's press on a phone, as
   back and continue do on every step (#434): the gaps and the sides give
   way, and a name may wrap inside its press. */
@media (max-width: 30rem) {
  .v-finish-actions { flex-wrap: nowrap; gap: .6rem; padding-inline: 0; }
  .v-finish-actions .v-btn { padding-inline: .7rem; font-size: .9rem; min-inline-size: 0; }
}
.v-finish .v-alert { justify-self: stretch; margin-block-end: 0; text-align: start; }
.v-finish-ready, .v-finish-live { margin: 0; font-size: 1.1rem; font-weight: 600; color: var(--v-ok); }
/* The address: grey, the card's own part gold; the two presses under it
   (Adam, 2026-09-09). */
.v-finish-address { margin: 0; overflow-wrap: anywhere; color: var(--v-ink-muted); font-weight: 600; }
.v-finish-links { display: flex; justify-content: center; align-items: center; gap: .75rem; margin-block-start: .5rem; }
/* Half the size of a press: these two only go somewhere (Adam, 2026-09-09). */
.v-finish-links .v-btn { margin-block-start: 0; padding: .2rem .55rem; font-size: .75rem; }
/* Its own class: .v-btn--icon is the link row's, padded for a full-size press. */
.v-finish-links .v-btn--copy { padding-inline: .5rem; }
.v-finish-copy { display: inline-flex; align-items: center; gap: .4rem; }
.v-finish-copy-label { font-size: .8rem; color: var(--v-ink-muted); cursor: pointer; }
.v-finish-copy-label.is-done { color: var(--v-ok); font-weight: 600; }
/* Air around the grey note and above the bottom row (Adam, 2026-09-09: "too
   crowded in the middle"). */
.v-finish-note { margin: .6rem 0 0; font-size: .85rem; color: var(--v-ok); }
/* The chosen languages the card will not show yet (#147). */
.v-finish-held { justify-self: stretch; margin-block-start: .6rem; font-size: .85rem; color: var(--v-ink-muted); text-align: start; }
.v-finish-held p, .v-finish-held ul, .v-finish-held ol { margin: 0; }
.v-finish-held > p { color: var(--v-ink); }
.v-finish-held ul { padding: 0; list-style: none; }
.v-finish-held > ul { margin-block-start: 1.05rem; }
.v-finish-held > ul > li + li { margin-block-start: 1.5rem; }
.v-finish-held ol { padding-inline-start: 1.4rem; list-style: decimal; color: var(--v-danger); }
.v-finish-held-language { color: var(--v-ink); font-weight: 600; }
.v-finish-held-flag { vertical-align: middle; margin-inline-end: .25rem; }
/* The languages the card goes on the air in, under the ready line, each
   name with its flag standing above it (#147, 3.6b). */
.v-finish-languages { display: flex; flex-wrap: wrap; justify-content: center; gap: 1.25rem; margin: .5rem 0 0; padding: 0; list-style: none; font-weight: 600; }
.v-finish-ready-language { display: inline-flex; flex-direction: column; align-items: center; vertical-align: bottom; }

/* The site's own "are you sure" box (step 1.4). */
.v-dialog {
  inline-size: min(92vw, 26rem); padding: 1.25rem 1.4rem; border: 1px solid var(--v-line); border-radius: var(--v-radius);
  background: var(--v-surface); color: var(--v-ink); box-shadow: var(--v-shadow);
}
.v-dialog::backdrop { background: rgba(0, 0, 0, .6); }

/* Whatever pop-up is open, the page behind it holds still (Adam,
   2026-10-01): a scroll on the backdrop, or past the end of a list inside
   the pop-up, moved the page under the blur. The page is locked while any
   modal dialog stands, and comes back where it was when the last one
   shuts; a scrolling list inside a pop-up keeps its scroll to itself.
   The scroll bar's room is kept while the page is locked, so a long page
   does not jump sideways as its bar goes; a short page may shift behind
   the blur instead, against an empty strip beside every short page with
   nothing open (Adam, 2026-10-01). */
html:has(dialog:modal) { overflow: hidden; scrollbar-gutter: stable; }
dialog, dialog .v-look-set { overscroll-behavior: contain; }

/* The wait a save makes visible (#122). The whole screen dims and blurs
   behind it while the step is on its way to the server, and because it
   is a modal dialog nothing under it takes a press, a tab or the reader.
   The box itself carries no ground of its own: the spinner and the word
   sit straight on the veil.

   Only while it is open. A display of its own beats the browser's rule
   for a closed dialog, and the veil then outlives its own close as a
   spinner standing in the step (Adam's hand test, 2026-09-12). */
.v-saving[open] {
  margin: auto; padding: 0; border: 0; background: none; color: var(--v-ink);
  display: flex; flex-direction: column; align-items: center; gap: .7rem;
  /* showModal() puts the focus on the veil itself, and the first key
     pressed against it draws the browser's focus ring around the spinner
     (Adam's hand test, 2026-09-12: "a blue rectangle over the saving
     animation"). Taking a ring off something that can be acted on would
     be wrong; there is nothing here to act on, no press, no field and no
     way through, so the ring points at nothing and only says the veil
     took a key. */
  outline: none;
}
.v-saving::backdrop { background: rgba(0, 0, 0, .72); backdrop-filter: blur(4px); }
.v-saving .v-spinner { display: block; inline-size: 2rem; block-size: 2rem; border-width: 3px; }
.v-saving-word { margin: 0; font-size: 1.05rem; }
.v-dialog-title { margin: 0 0 .6rem; font-size: 1.15rem; }
/* The body is written as text, never as markup, so a line break in the
   string is a line break on the screen (Adam, 2026-09-17). */
.v-dialog-body { margin: 0 0 1.1rem; color: var(--v-ink-muted); white-space: pre-line; }
/* The line that says what the press does, in the page's own red, with the
   rest of the body under it in the dialog's colour (Adam, 2026-09-17). */
.v-dialog-lead { display: block; }
/* An address made final (#462, round 9): alone on its line, then about
   two lines' gap before the once-only line. */
.v-dialog-address { display: block; color: var(--v-ink); overflow-wrap: anywhere; }
.v-dialog-after { display: block; margin-block-start: 2lh; }
.v-dialog-lead--bad { color: var(--v-danger); }
/* What is about to go public, box by box (step 1.4b). The list scrolls
   inside the box so the buttons stay in view however much changed. */
/* The part that scrolls carries its own ground, the same wash the card's
   own "about" block uses, so it reads as one panel rather than as text
   running off the bottom of the dialog (Adam, 2026-09-11). */
.v-dialog-list {
  margin: 0 0 1.1rem; padding: .75rem .9rem; list-style: none; max-block-size: 40vh; overflow-y: auto;
  background: color-mix(in srgb, var(--v-ink) 6%, transparent); border-radius: var(--v-radius);
}
.v-dialog-list[hidden] { display: none; }
.v-dialog-item { display: flex; flex-direction: column; margin-block-end: .8rem; overflow-wrap: anywhere; }
.v-dialog-name { font-weight: 600; }
.v-dialog-line { margin-block-start: .3rem; color: var(--v-ink-muted); font-size: .85rem; }
/* The two lines read as a diff: what goes is red, what arrives is green,
   and a rewrite of a long text is neither (Adam, 2026-09-07). */
.v-dialog-was { color: var(--v-danger); }
.v-dialog-will, .v-dialog-created { color: var(--v-ok); }
/* The words "היה" and "יהיה" name the side; the colour belongs to the
   value they introduce (Adam, 2026-09-08). */
.v-dialog-side { color: var(--v-ink); }
/* The palette's own strip beside its name (Adam, 2026-09-19): smaller than
   the pop-up's, and sitting on the line the words are on. */
.v-dialog-swatch { margin-inline-start: .5rem; vertical-align: -.3rem; }
.v-dialog-swatch .v-palette-band { inline-size: .9rem; block-size: 1.1rem; }
.v-dialog-note { color: var(--v-ink-muted); }
.v-dialog-note--added { color: var(--v-ok); }
.v-dialog-note--cleared { color: var(--v-danger); }
.v-actions--dialog { justify-content: flex-end; }
.v-actions--dialog .v-btn { margin-block-start: 0; }
/* On a phone the site's "are you sure" box keeps its two presses on one row,
   halves of it, a long label wrapping inside its own press (Adam's hand
   test, 2026-10-02: the leave dialog's two stacked read as two dialogs). */
@media (max-width: 39.99rem) {
  .v-dialog[data-controller~="confirm-dialog"] .v-actions--dialog { flex-wrap: nowrap; }
  .v-dialog[data-controller~="confirm-dialog"] .v-actions--dialog .v-btn { flex: 1 1 0; min-inline-size: 0; padding-inline: .8rem; text-align: center; }
}

/* The leave dialog's two presses, one size (#325, round 2). Two classes:
   .v-actions comes later in this file and centres its row. */
.v-actions.v-actions--leave { align-items: stretch; }
.v-actions--leave .v-btn { flex: 1 1 0; }

/* A heading with a press in the box's far corner: the contact page's way
   home (#325). The press keeps to its corner; the heading takes the rest. */
.v-title-row { display: flex; align-items: flex-start; justify-content: space-between; gap: .6rem; }
.v-title-row .v-home-press { flex: none; margin-block-start: 0; }
/* The leave dialog's way back to the step (round 3): the contact box's
   corner press, and gone on every other ask; .v-btn sets a display. */
.v-title-row .v-dialog-stay { flex: none; margin-block-start: 0; }
.v-dialog-stay[hidden] { display: none; }
/* The editor's title row (round 3 of #445): its small press centred on
   the title line; the row, not the line, keeps the room under it. */
.v-title-row--centred { align-items: center; margin-block-end: 1rem; }
.v-title-row--centred .v-signed-in-as { margin-block-end: 0; }
.v-title-row--centred .v-btn.v-btn--small { padding-block: .3rem; }
/* The step box's own way home is for a wide screen: a phone has the top
   link, and two home presses on one phone screen is one too many. */
@media (max-width: 39.99rem) {
  .v-btn.v-editor-home { display: none; }
}
/* A row whose last press sits at the far end: settings' way home beside
   the withdraw press (#325). */
.v-actions--ends { flex-wrap: nowrap; }
.v-actions--ends > :last-child { margin-inline-start: auto; }
/* The agree press is the big green one; on a phone its sides narrow so the
   way home fits beside it. */
@media (max-width: 39.99rem) {
  .v-actions--ends .v-btn--go { padding-inline: 1.4rem; }
}

/* The consent box a new account is asked for (#248). The terms line reads
   as a note, the box reads as the one thing to do. */
.v-consent-terms { margin: 0 0 1rem; color: var(--v-ink-muted); font-size: .95rem; }
/* The whole line is the target, not the square alone: a thumb on a phone
   is wider than 1.1rem. */
.v-consent-box { display: flex; align-items: flex-start; gap: .55rem; cursor: pointer; line-height: 1.4; }
.v-consent-box input { margin: .15rem 0 0; inline-size: 1.1rem; block-size: 1.1rem; flex: none; accent-color: var(--v-accent); }
/* The terms and the box on the sign-up screen itself (#400). */
.v-consent-inline { margin-block: 1rem; }

/* The line under each of the two forms that leads to the other (#400),
   and the sign-up link inside the sign-in screen's "no account" alert, in
   the alert's own colour so it keeps the alert's contrast. */
.v-auth-switch { margin-block-start: 1.25rem; }
/* The way back to the home page, above each screen's heading (#400). */
.v-back-home { margin-block: 0 .75rem; font-size: .95rem; }
.v-alert a { color: inherit; font-weight: 600; }

/* The creation pop-up (#146): the address, then the languages. Wider than
   the "are you sure" box, since it holds the address page. */
.v-create { inline-size: min(92vw, 28rem); }
/* The answer under the address box has its room before it arrives, as
   many lines as the longest answer takes, so the pop-up never grows under
   the realtor's eyes (Adam's hand test, 2026-09-14). The margin is held
   too: an empty .v-hint gives up its margin, and this one must not. */
.v-create .v-hint[data-card-create-target="message"] { margin-block: .45rem 0; min-block-size: 2lh; }
@media (max-width: 30rem) { .v-create .v-hint[data-card-create-target="message"] { min-block-size: 3lh; } }
.v-create-set { margin: 0; padding: 0; border: 0; min-inline-size: 0; }
.v-create-set legend { padding: 0; }
/* The set's own hint alone: a live check's line inside a set keeps its
   green and red (#464, round 5). */
.v-create-set > .v-hint { margin-block: 0 .9rem; color: var(--v-ink-muted); }
/* The main language: four big presses, two to a row, one of them lit. The
   radio itself covers its press, unseen, so the press is the radio for a
   pointer, a keyboard and a reader alike. */
.v-create-choices { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.v-create-choice {
  position: relative; display: flex; align-items: center; justify-content: center; gap: .55rem;
  min-block-size: 3.5rem; padding: .5rem; font-size: 1.05rem;
  border: 1px solid var(--v-line); border-radius: var(--v-radius); cursor: pointer;
}
.v-create-choice:has(:checked) {
  border-color: var(--v-accent); font-weight: 600;
  background: var(--v-accent-wash);
}
.v-create-choice:has(:focus-visible) { outline: 2px solid var(--v-accent); outline-offset: 2px; }
/* An imported card's address step (#462): the current address between
   the two choices, and the box for a new one only while "new" is chosen
   (Adam's hand test of #464, round 1); a wide gap before back and save
   so the screen falls into parts at a glance (round 3). */
.v-address-step { margin-block: 1rem 3.5rem; }
/* Round 2: each press on its own line at the start side, as wide as its
   words, a little smaller than the create dialog's, and the unchosen one
   on the field ground so it reads as a press, not a gap. */
.v-address-step .v-create-choice {
  inline-size: fit-content; min-block-size: 2.75rem; padding-inline: 1.1rem;
  font-size: .95rem; background: var(--v-field);
}
.v-address-step .v-create-choice:has(:checked) { background: var(--v-accent-wash); }
/* Midway between keep and "new" (round 7). One line, the caption then
   the address in a box on the unchosen press's ground; on a narrow phone
   the box drops under the caption (round 5). */
.v-address-current {
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .5rem;
  margin-block: 1.25rem; font-size: .9rem;
}
.v-address-caption { color: var(--v-ink-muted); }
.v-address-box { padding: .2rem .55rem; border-radius: var(--v-radius); background: var(--v-field); overflow-wrap: anywhere; min-inline-size: 0; }
.v-address-new { margin-block-start: .6rem; }
/* The name on its own: it moves to the next line whole, never split at a
   hyphen, and breaks only when longer than the line itself (round 9). */
.v-address-step .v-address-tail, .v-dialog-address .v-address-tail { display: inline-block; max-inline-size: 100%; overflow-wrap: anywhere; }
.v-address-new .v-address-preview { font-size: .85rem; }
.v-address-tip { margin-block: 0 .5rem; font-size: .85rem; color: var(--v-ink-muted); }
/* The Hebrew placeholder reads right to left; a typed name stays LTR. */
.v-address-new .v-input:placeholder-shown { direction: rtl; text-align: right; }
/* Hidden, not removed: the box keeps its room while keep is chosen, so
   picking "new" shows it in place and nothing moves (round 4); hidden
   this way it is out of the tab order and unread by a screen reader. */
.v-address-step:has(input[name="choice"][value="keep"]:checked) .v-address-new { visibility: hidden; }
.v-create-input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.v-create-flag { display: block; border-radius: 2px; }
.v-create-others { display: grid; gap: .55rem; margin-block-start: 1.25rem; }
.v-create-other { display: flex; align-items: center; gap: .55rem; cursor: pointer; }
.v-create-other[hidden] { display: none; }
.v-create-other input { margin: 0; inline-size: 1.1rem; block-size: 1.1rem; accent-color: var(--v-accent); }
/* The create pop-up's presses sit at the start (the right in Hebrew), back
   first, the way on after it (Adam's hand test, #384). */
.v-create .v-actions--dialog { margin-block-start: 1.25rem; justify-content: flex-start; }

/* The card's languages page (#163): a table, the main language's row in
   the accent colour and named so in words, never by the colour alone. */
/* Rounded like every other panel on the page (Adam, 2026-09-17). A table
   box ignores overflow, so a radius on the table clips nothing: the rows'
   own bands carry the corners, which is why the borders are separate. */
.v-languages { inline-size: 100%; border-collapse: separate; border-spacing: 0; }
.v-languages th, .v-languages td { padding: .6rem .5rem; text-align: start; border-block-end: 1px solid var(--v-line); }
/* Each language its own band, told apart by a lift off the page and a line
   heavier than the page's own (Adam, 2026-09-17). The main language's
   accent band wins over the grey, so it is named here again. */
.v-languages tbody tr { background: color-mix(in srgb, var(--v-ink) 6%, transparent); }
.v-languages tbody th, .v-languages tbody td { border-block-end: 2px solid color-mix(in srgb, var(--v-ink) 36%, transparent); }
/* The first and last bands are the block's own corners; the head and the
   add row carry no band, so the rounding belongs here. The last band's
   line would cut across its rounded edge, so it goes. */
.v-languages tbody tr:first-child th { border-start-start-radius: var(--v-radius); }
.v-languages tbody tr:first-child td:last-child { border-start-end-radius: var(--v-radius); }
.v-languages tbody tr:last-child th { border-end-start-radius: var(--v-radius); }
.v-languages tbody tr:last-child td:last-child { border-end-end-radius: var(--v-radius); }
.v-languages tbody tr:last-child th, .v-languages tbody tr:last-child td { border-block-end: 0; }
.v-languages thead th { font-size: .8rem; font-weight: 500; color: var(--v-ink-muted); }
.v-languages tbody th { font-weight: 500; }
.v-languages td:last-child { text-align: end; }
.v-languages-name { display: inline-flex; align-items: center; gap: .55rem; }
/* Only the main language's tag is left this colour: every other tag
   names its own state and takes that state's tone. So this is the
   word that sits on the accent wash (#214). */
.v-languages-tag { display: block; font-size: .8rem; color: var(--v-accent-on-wash); }
.v-languages tbody tr.v-languages-main { background: var(--v-accent-wash); }
/* Edit beside Activate or Deactivate; button_to's form takes no room. */
.v-languages-actions { display: inline-flex; flex-wrap: wrap; justify-content: flex-end; gap: .4rem; }
.v-languages-actions form { display: contents; }
/* A deactivated language (#164): its name greyed, its tag saying so in
   words, never the grey alone. */
.v-languages-off .v-languages-name { color: var(--v-ink-muted); }
/* Where an added language stands (Adam, 2026-09-17): green while the card
   shows it, red once its support is stopped. The words carry the same
   meaning, so the colour is never alone. The two tones are the page's own
   — the ok alert's green and the required tag's red. */
.v-languages-tag--on { color: var(--v-ok-soft); }
.v-languages-tag--off { color: var(--v-danger); }
/* A language the realtor added and has not written yet (#173): the third
   state, in the amber the site's warnings already wear. */
.v-languages-tag--waiting { color: var(--v-warn-soft); }
/* The up-to-date pill (#165), in the middle column between the name and
   the presses (Adam, 2026-09-17): green while the main words are as this
   language last saw them, the same amber once one changed. Words again,
   never the colour alone. */
.v-languages td.v-languages-fresh { text-align: center; }
.v-languages-fresh .v-languages-tag { white-space: nowrap; }
/* The line under the count: what the count means for the realtor (Adam,
   2026-09-17). */
.v-languages-note { color: var(--v-ink-muted); font-size: .75rem; }
/* Room between the "editing" line and the table (Adam, 2026-09-17). */
.v-shell--languages .v-editing-line { margin-block-end: 2rem; }
/* On a wide screen the box grows so each language is one line — name and
   tag, pill, presses — with room between them (Adam, 2026-09-17, on his
   hand test, after the presses wrapped in the phone-width box). On a phone
   the box stays as it was and the row stacks: name, pill and two presses
   do not fit one line there. */
@media (min-width: 48rem) {
  .v-shell--languages { max-inline-size: 46rem; }
  .v-languages tbody th, .v-languages tbody td { padding: .9rem 1rem; white-space: nowrap; }
  .v-languages-actions { flex-wrap: nowrap; }
  .v-languages tbody th .v-languages-tag { display: inline-block; margin-inline-start: .75rem; }
  /* The names take one width, so the tags start on one line down the
     table, like a column without its border (Adam's hand test, 2026-09-17). */
  .v-languages tbody th .v-languages-name { min-inline-size: 7.5rem; }
}
/* On a phone the columns go (Adam, 2026-09-17, on his hand test: three
   columns in 330px wrapped the presses word by word). Each language is a
   stacked block: flag, name and tag on one line, the pill under them when
   there is one, the presses side by side across the block. */
@media (max-width: 47.99rem) {
  .v-languages tbody tr { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem .75rem; padding: .8rem .9rem;
    border-block-end: 2px solid color-mix(in srgb, var(--v-ink) 36%, transparent); }
  .v-languages tbody tr:first-child { border-start-start-radius: var(--v-radius); border-start-end-radius: var(--v-radius); }
  .v-languages tbody tr:last-child { border-end-start-radius: var(--v-radius); border-end-end-radius: var(--v-radius); border-block-end: 0; }
  .v-languages tbody th, .v-languages tbody td { display: block; padding: 0; border: 0; border-radius: 0; flex: 1 1 100%; }
  /* Everything centred but the two presses, which fill the block (Adam,
     2026-09-17, his phone hand test). */
  .v-languages tbody th { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: .3rem .75rem; }
  .v-languages tbody th .v-languages-tag { display: inline; }
  .v-languages-fresh:not(:has(.v-languages-tag)) { display: none; }
  .v-languages td:last-child { text-align: center; }
  .v-languages-actions { display: flex; inline-size: 100%; }
  .v-languages-actions .v-btn { flex: 1; text-align: center; }
  .v-languages tbody .v-btn { white-space: nowrap; }
}
.v-languages-tag--fresh { color: var(--v-ok-soft); }
.v-languages-tag--stale { color: var(--v-warn-soft); }
/* The title and the press to the card on one line, the press at the far
   end of it (Adam, 2026-09-17), wrapping under the title on a narrow
   phone. */
.v-languages-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .5rem 1rem; }
.v-languages-head .v-title { margin-block-end: .25rem; }
/* The add-languages press sits where the table starts, not where the
   actions column ends (Adam, 2026-09-17): the row spans both columns, so
   the actions column's end alignment above would otherwise carry it, and
   it is the last cell of its row, so this selector has to outweigh it. */
.v-languages tfoot td { border-block-end: 0; padding-block-start: 1rem; }
.v-languages tfoot td:last-child { text-align: start; }
.v-languages-add > summary { list-style: none; cursor: pointer; display: inline-block; }
.v-languages-add > summary::-webkit-details-marker { display: none; }
.v-languages-add[open] > summary { display: none; }
.v-languages-add .v-create-others { margin-block: 0 1rem; }

/* The long form (#163): the language's flag before each box's name, and
   the links under a divider like the card's group headings, each link in
   the form's own box: its main address and name, read-only, over the box
   for its name in the form's language. */
.v-field-flag { flex: none; }
.v-field .v-label-row:has(.v-field-flag) { justify-content: flex-start; align-items: center; gap: .45rem; }
.v-label-row:has(.v-field-flag) .v-field-flag { margin-block-end: .6rem; }
.v-language-links-heading {
  display: flex; align-items: center; gap: .6rem; margin: 1.4rem 0 .9rem;
  color: var(--v-ink-muted); font-size: .8rem; font-weight: 500; letter-spacing: .04em;
}
.v-language-links-heading::after { content: ""; flex: 1; border-block-start: 1px solid var(--v-line); }
.v-language-link-caption { display: flex; align-items: center; gap: .45rem; margin: 0; font-size: .8rem; color: var(--v-ink-muted); }
.v-language-link-main { margin: 0 0 .6rem; font-weight: 500; }
/* The main language's address and name on a grey ground, so they stand
   out from the captions (Adam's hand test, 2026-09-17). */
.v-language-link-address, .v-language-link-main {
  padding: .3rem .55rem; border-radius: 4px;
  background: color-mix(in srgb, var(--v-ink) 12%, transparent);
}
.v-language-link-address { margin: 0 0 .5rem; font-size: .9rem; overflow-wrap: anywhere; }

/* Just published: the note on the account page, and the confetti over it. */
.v-congrats { margin-block-end: 1.5rem; padding: 1rem 1.2rem; border: 1px solid var(--v-ok-line); border-radius: var(--v-radius); background: var(--v-ok-bg); text-align: center; }
.v-congrats .v-title { margin-block-end: .6rem; }
.v-congrats-body { margin: 0; }
.v-congrats-scan { margin-block-start: 2.2rem; }
.v-congrats .v-preview-qr { margin-inline: auto; }
.v-confetti { position: fixed; inset: 0; pointer-events: none; z-index: 10; }
@media (max-width: 63.99rem) {
  .v-pane.is-off { display: none; }
  /* On a phone the tab is the phone: no bezel, no height cap, the card at
     full width and the frame as tall as the card (the controller sets it),
     so the page scrolls rather than a box inside a box. A landscape phone
     made the capped frame a slot (Adam's phone, 2026-09-07). */
  .v-phone { inline-size: 100%; max-block-size: none; aspect-ratio: auto; border: 0; border-radius: 0; background: none; }
  .v-phone-screen { min-block-size: 60vh; }
}
@media (min-width: 64rem) {
  /* Packed toward the side bar (Adam's hand test of #455): the body keeps
     5.5rem for the bar, which is 3.5rem wide closed, so the shell steps
     back by the difference and stands 1.5rem off the bar. What is left on
     the far side stays empty: the phone is as wide as the card it holds. */
  .v-shell--editor {
    max-inline-size: none; margin-inline: -2rem 0; padding-inline: calc(1.5rem + var(--v-steps-room, 0rem)) var(--v-shell-end, 1.25rem);
    grid-template-columns: minmax(24rem, 30rem) max-content; justify-content: start; gap: var(--v-preview-gap, 2.5rem); align-items: start;
  }
  .v-panes { display: none; }
  /* The same distance from the top as the shell padding puts it at before
     any scroll, or the pane hops that difference on the first scroll
     (Adam, 2026-09-09). */
  .v-preview { position: sticky; top: 3rem; }
  .v-shell--editor > .v-pane:not(.v-preview) { grid-column: 1; }
  .v-shell--editor > .v-preview { grid-column: 2; grid-row: 1; }
  /* The card at its true size, as wide as on its public address in a
     computer browser (the preview controller sets the frame's width), and
     the phone as tall as the window allows, so more of the card shows.
     The personal area's preview is the same phone (Adam, 2026-10-07). */
  .v-shell--editor .v-phone, .v-your-card-preview .v-phone { inline-size: auto; block-size: calc(100vh - 12.5rem); max-block-size: none; aspect-ratio: auto; }
  /* The preview is beside the editor here, so the line may name its side
     (#72); the phone's wording, which names none, goes. */
  .v-editor-welcome--beside { display: flex; }
  .v-editor-welcome--phone { display: none; }
}
/* A very wide window (Adam's hand test of #455, zoomed all the way out,
   and a 4K screen): past 77.5rem, the width the side bar, the step list,
   the box at its widest and the phone take together, the four stay one
   group in the middle of the window, the bar moving in with them. The
   phone is no taller than the card it holds needs (the preview
   controller measures it), so a tall window shows no empty phone below
   the card. Below that width nothing changes. The languages page,
   with no list, stays packed toward the bar. 100%, not 100vw: the
   width of the page and of the window less its scroll bar, which a
   pop-up's lock keeps; 100vw loses the bar's room under the lock, and
   the side bar jumped sideways. */
@media (min-width: 77.5rem) {
  body.v-has-side-bar:has(.v-shell--editor .v-steps) { --v-wide-side: calc((100% - 77.5rem) / 2); padding-inline-start: calc(5.5rem + var(--v-wide-side)); }
  body:has(.v-shell--editor .v-steps) .v-side-bar { inset-inline-start: var(--v-wide-side); }
  /* The scroll bar's room kept on a short page too, so a pop-up's lock
     or the save veil never narrows the page and moves the group: the
     group stands far from the edge, so the empty strip goes unseen. */
  html:has(.v-shell--editor .v-steps) { scrollbar-gutter: stable; }
  .v-shell--editor .v-phone, .v-your-card-preview .v-phone { block-size: min(calc(100vh - 12.5rem), calc(var(--v-card-needs, 100vh) + 16px)); }
}

/* The arrow from the box with focus to where it shows on the card (#436,
   a try-out): drawn over the page by field-pointer, which places it in
   the window's own coordinates, never in the way of a press. The look's
   accent, which holds 3:1 on the page and on the field ground in every
   look. A short fade as it appears for a new box; nothing under reduced
   motion. */
.v-pointer { position: fixed; inset: 0; inline-size: 100%; block-size: 100%; z-index: 5; pointer-events: none; overflow: visible; }
.v-pointer[hidden] { display: none; }
.v-pointer path { fill: none; stroke: var(--v-accent); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
@keyframes v-pointer-in { from { opacity: 0 } to { opacity: 1 } }
.v-pointer.is-new path { animation: v-pointer-in .25s ease-out both; }
@media (prefers-reduced-motion: reduce) { .v-pointer.is-new path { animation: none; } }

/* The pill above the frame: green "updated" at rest, yellow with a
   spinner while a refresh is in flight, red when it did not land (Adam,
   2026-09-07; the fade was dropped the same day, he wanted the green
   there whenever the card is current). */
.v-pill {
  display: inline-flex; align-items: center; gap: .45rem; min-block-size: 1.7rem; margin: 0; padding: .2rem .85rem;
  border-radius: 999px; font-size: .85rem; font-weight: 500; opacity: 0;
}
.v-pill--updating { opacity: 1; color: var(--v-warn); background: var(--v-warn-bg); }
.v-pill--updated { opacity: 1; color: var(--v-ok); background: var(--v-ok-bg); }
.v-pill--failed { opacity: 1; color: var(--v-danger); background: var(--v-danger-bg); }
.v-spinner {
  display: none; inline-size: .8rem; block-size: .8rem; border-radius: 50%;
  border: 2px solid currentColor; border-inline-end-color: transparent; animation: v-spin .8s linear infinite;
}
.v-pill--updating .v-spinner { display: inline-block; }
@keyframes v-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .v-spinner { animation: none; } }

/* The "add link" menu: a list of types, each with its ceiling. */
.v-menu { position: relative; display: inline-block; }
.v-menu > summary { list-style: none; }
.v-menu > summary::-webkit-details-marker { display: none; }
.v-menu-list {
  position: absolute; inset-inline-start: 0; top: calc(100% + .3rem); z-index: 2; min-inline-size: 14rem;
  padding: .3rem; display: grid;
  background: var(--v-surface); border: 1px solid var(--v-line); border-radius: var(--v-radius); box-shadow: var(--v-shadow);
}
.v-menu-item {
  display: flex; justify-content: space-between; gap: .8rem; align-items: baseline;
  padding: .5rem .7rem; border: 0; border-radius: calc(var(--v-radius) - 4px);
  background: none; color: var(--v-ink); font: inherit; text-align: start; cursor: pointer;
}
.v-menu-item:hover { background: var(--v-line); }
.v-menu-item.is-full { color: var(--v-ink-muted); }
.v-menu-item.is-full .v-menu-name { text-decoration: line-through; }
.v-menu-count--full { color: var(--v-ok); }

/* Link rows on the links step. One layout at every width (Adam's desktop,
   2026-09-07: the wide-screen grid had no place for the label line and
   lost the frame): each row in its own frame, type, icon and trash on the
   first line, the address on the second, the label and its counter on a
   third when the type is "other". The type box is only as wide as its word. */
/* The rows end with a box's own air, so the Next line under them sits
   where it sits under the last box on every other step (#325, reviewer). */
.v-link-rows { display: grid; gap: .6rem; margin: .9rem 0; }
.v-link-row { padding: .6rem; border: 1px solid var(--v-frame); border-radius: var(--v-radius); }
/* Rows by number, each line under the box it speaks for. No row gap: a
   line not drawn makes an empty track, so the space is each item's own. */
.v-link-row-fields { display: grid; grid-template-columns: auto 1fr auto; column-gap: .4rem; align-items: center; }
.v-link-row-fields [hidden] { display: none; }
.v-link-row-fields .v-menu--type { grid-row: 1; grid-column: 1; }
.v-link-row-fields .v-link-row-num { grid-row: 1; grid-column: 1; font-weight: 700; }
.v-menu--type > summary { display: inline-flex; align-items: center; gap: .5rem; cursor: pointer; }
.v-menu--type .v-menu-list { min-inline-size: 10rem; }
.v-link-row-fields .v-link-row-icon { grid-row: 1; grid-column: 2; }
.v-link-row-fields .v-btn--icon { grid-row: 1; grid-column: 3; }
/* The handle hint sits between the type and the box (#480). */
.v-link-row-fields .v-link-row-handle { grid-row: 2; grid-column: 1 / -1; margin-block: .4rem 0; color: var(--v-ink-muted); }
.v-link-row-fields input[type="url"] { grid-row: 3; grid-column: 1 / -1; margin-block-start: .4rem; }
.v-link-row-fields [data-link-row-target="note"] { grid-row: 4; grid-column: 1 / -1; }
.v-link-row-fields [data-field-error-attribute-value="url"] { grid-row: 5; grid-column: 1 / -1; }
/* The label takes 70% of the line, room for its 20 characters; the
   counter sits right after it with a small gap. */
.v-link-row-fields .v-link-row-caption { grid-row: 6; grid-column: 1 / -1; margin-block-start: .6rem; font-size: .85rem; }
.v-link-row-fields input[name$="[label]"] { grid-row: 7; grid-column: 1 / -1; inline-size: 70%; margin-block-start: .4rem; }
.v-link-row-fields [data-field-error-attribute-value="label"] { grid-row: 8; grid-column: 1 / -1; }
.v-link-row-fields .v-counter { grid-row: 7; grid-column: 1 / -1; align-self: center; justify-self: end; inline-size: 30%; padding-inline-start: .6rem; text-align: start; }
/* The page's own ink, not white (#187): a link with no network of its own
   wears the colour the rest of the words wear, so it is still there on a
   light page. */
.v-link-row-icon { color: var(--v-ink); font-size: 1.1rem; text-align: center; }
/* Each network in its own colour, so the row reads at a glance (Adam,
   2026-09-07). TikTok has no rule of its own here: its mark is black with
   cyan and pink edges, neither of which reads as "TikTok" alone, so the
   row's default ink carries it. LinkedIn is the one with a token, because
   the shade lightened to sit apart from Facebook's on a near-black page
   disappears on a white one (#197). The other three take a value per
   scheme, the card's own (#399): Rose's deep pink panel put each one
   colour under 3:1. The plain light colour first is for a browser that
   does not know light-dark(). */
.v-link-row-icon.fa-facebook { color: #0860f0; color: light-dark(#0860f0, #1877f2); }
.v-link-row-icon.fa-instagram { color: #c13584; color: light-dark(#c13584, #e3366f); }
.v-link-row-icon.fa-youtube { color: #cc0000; color: light-dark(#cc0000, #ff3333); }
.v-link-row-icon.fa-linkedin { color: var(--v-linkedin); }
.v-input--select { padding-inline-end: .8rem; }
/* The trash sits level with the type box: same height, same corners. Two
   classes, because the plain .v-btn rule comes later in this file and was
   winning back its top margin and round shape (Adam's screenshot,
   2026-09-07). */
.v-btn.v-btn--icon { padding: .7rem .9rem; margin-block-start: 0; align-self: stretch; border-radius: 10px; line-height: inherit; }
.v-link-row .v-counter { margin: .4rem 0 0; }

/* The account's email offered under the email box, one tap to take it. */
.v-suggest-wrap { position: relative; }
.v-suggest {
  position: absolute; inset-inline-start: 0; inset-inline-end: 0; top: calc(100% + .2rem); z-index: 2;
  margin: 0; padding: .25rem; list-style: none;
  background: var(--v-surface); border: 1px solid var(--v-line); border-radius: var(--v-radius); box-shadow: var(--v-shadow);
}
.v-suggest[hidden] { display: none; }
.v-suggest-item {
  display: block; inline-size: 100%; padding: .55rem .7rem; text-align: start;
  font: inherit; color: var(--v-ink); background: none; border: 0; border-radius: 8px; cursor: pointer;
}
.v-suggest-item:hover, .v-suggest-item:focus-visible { background: var(--v-line); }

/* The one thing on the address page that must not be missed. */
.v-warning { margin: .75rem 0 1.5rem; }
.v-warning-label { color: var(--v-warn); font-weight: 700; }
.v-example { margin: 0 0 .6rem; }

.v-alert {
  background: var(--v-danger-bg);
  border: 1px solid var(--v-danger-line);
  color: var(--v-danger);
  border-radius: 10px;
  padding: .7rem .9rem;
  margin-block-end: 1.25rem;
  font-size: .95rem;
}

.v-field { margin-block-end: 1.25rem; }
/* In the editor every input group sits in its own box, like a link row:
   a detail and the box for how it reads on the card belong together, and
   the frame says so (Adam, 2026-09-08). A nested box draws no frame.
   The group also carries the panel colour, because the editor has no panel
   of its own and its groups sit straight on the page: a box's ground is
   only a ground if something different is behind it, and on the light look
   --v-page is within 1.04:1 of --v-field (#201). */
.v-shell--editor .v-field { padding: .7rem .8rem; border: 1px solid var(--v-frame); border-radius: var(--v-radius); margin-block-end: .9rem; background: var(--v-surface); }
.v-shell--editor .v-field .v-field { padding: 0; border: 0; border-radius: 0; margin-block-end: 0; background: none; }
/* The second phone behind a press until there is one (Adam, 2026-09-08). */
.v-reveal > summary, .v-reveal-press { list-style: none; cursor: pointer; color: var(--v-accent); font-size: .95rem; margin-block-end: .9rem; }
/* The links step's add press wears the reveal's look (round 2 of #445). */
.v-reveal-press { padding: 0; border: 0; background: none; font-family: inherit; }
.v-reveal > summary::-webkit-details-marker { display: none; }
.v-reveal[open] > summary { display: none; }
.v-remove { display: inline-block; margin-block-start: .6rem; padding: 0; border: 0; background: none; font: inherit; font-size: .9rem; color: var(--v-danger-strong); cursor: pointer; }
.v-remove:hover, .v-remove:focus-visible { text-decoration: underline; }
.v-label { display: block; margin-block-end: .4rem; font-size: .9rem; color: var(--v-ink-muted); }
/* In the editor the label's words are white; the tag after them stays
   grey (Adam, 2026-09-09). */
.v-shell--editor .v-label { color: var(--v-ink); }
/* The contact page's labels in the theme's accent, the Send press's own
   colour (Adam, 2026-09-27). Two classes, because the grey rule above
   carries the same weight and comes later than .v-accent. */
.v-label.v-accent { color: var(--v-accent); }

/* Every box a realtor types into, in the editor and everywhere else: the
   fields, the selects, the text areas, and the <summary> the links step
   draws in place of a native list. The ground says a box is there and the
   edge draws where it ends; --v-line was too faint to do the second job on
   its own ground (about 1.2:1), and an empty box has no content of its own
   to identify it (#201; WCAG 2.1 1.4.11). */
.v-input {
  inline-size: 100%;
  padding: .7rem .9rem;
  border: 1px solid var(--v-frame);
  border-radius: 10px;
  font: inherit;
  background: var(--v-field);
  color: var(--v-ink);
}
.v-input:focus-visible { border-color: var(--v-accent); }
/* An address box runs left to right, so its Hebrew example ("לדוגמה:
   https://...") put "לדוגמה:" on the left. While empty it reads right to
   left; what the realtor types still runs left to right (#438). */
[dir="rtl"] .v-input:is([type="url"], [type="email"]):placeholder-shown { direction: rtl; }

.v-actions { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; }

.v-btn {
  display: inline-block;
  padding: .7rem 1.4rem;
  border-radius: 999px;
  border: 1px solid var(--v-line);
  background: var(--v-surface);
  color: var(--v-ink);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  margin-block-start: .75rem;
}
/* Two classes, not one: .v-btn comes later in this file and would win at
   the same specificity, taking the padding, the size and the margin back
   — the trap this file already documents for .v-btn--icon (#77). */
.v-btn.v-btn--small { padding: .4rem .8rem; font-size: .85rem; margin-block-start: 0; }
.v-btn--primary { background: var(--v-accent); border-color: var(--v-accent); color: var(--v-on-accent); }
/* After .v-btn, which sets the colour too: unpublish, and its go-ahead
   in the dialog, read red (Adam, 2026-09-07). */
.v-btn--danger { color: var(--v-danger); border-color: var(--v-danger-line); }
/* The account page's tray, one colour per press (Adam, 2026-09-08):
   edit blue, the card lavender, unpublish orange (a shade warmer than
   the draft badge, undoable), delete red above. */
.v-btn--accent { color: var(--v-accent-soft); border-color: var(--v-accent-line); }
.v-btn--soft { color: var(--v-soft-ink); border-color: var(--v-soft-line); }
.v-btn--warn { color: var(--v-warn-strong); border-color: var(--v-warn-line); }
/* A small green press, the ok alert's green: Activate on the languages
   page (Adam, 2026-09-17). Not .v-btn--go, which is the fourth screen's
   one big publish press. */
.v-btn--ok { color: var(--v-ok-soft); border-color: var(--v-ok-line); }
/* A press that only goes somewhere: blue, text and border, the way the
   orange and red ones carry their tone (Adam, 2026-09-09). */
.v-btn--link { color: var(--v-accent-soft); border-color: var(--v-accent-line); }
/* The press under the website box (#64), where the echoed address used to
   sit: the room the hint it replaced took, and the explicit rule the
   `hidden` attribute needs, since .v-btn sets a display of its own. */
.v-web-open { margin-block-start: .45rem; }
.v-web-open[hidden] { display: none; }
/* The fourth screen's publish press: green, and the biggest on the page
   (#50). After .v-btn, like the other tones, or the base background wins. */
.v-btn--go { background: var(--v-go); border-color: var(--v-go-line); color: var(--v-on-go); font-size: 1.15rem; padding: .9rem 2.4rem; }
.v-btn:hover { filter: brightness(.97); }

/* Validity feedback. The browser's own bubble is switched off on the form,
   so these carry the whole signal — colour plus a line of text, never colour
   alone, since a red border says nothing to a colour-blind reader. */

.v-input.is-valid   { border-color: var(--v-ok-strong); }
.v-input.is-invalid { border-color: var(--v-danger-strong); }
.v-input.is-warned  { border-color: var(--v-warn); }
/* Refused by the server (field-error), after is-valid so a live check
   that passes the value never paints a refused box green (#444 sweep). */
.v-input.is-refused { border-color: var(--v-danger-strong); }
/* A box in another language's form whose main word changed since that
   language was last saved (#165): the warned edge, and under a one-line
   box the main word as it stands now, after the main language's flag.
   After the validity rules so the yellow edge outlives a typed value's
   green until Save. */
.v-field--stale .v-input { border-color: var(--v-warn); }
.v-field-main { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; margin: .45rem 0 0; font-size: .85rem; color: var(--v-warn-soft); }
.v-field-main-word { color: var(--v-ink); font-weight: 500; }

/* Wrapped anywhere: a hint can hold an unbroken string — a dialled number,
   an address inside a message — and without the wrap it slid past the
   form's edge on desktop and widened the whole page on a phone (Adam,
   2026-09-09, bundle A). */
.v-hint { margin-block: .45rem 0; font-size: .85rem; min-block-size: 1.2em; overflow-wrap: anywhere; }
/* A line with nothing to say takes no room (Adam, 2026-09-08: an empty
   line pushed the second phone's remove press down) -- but it stays
   rendered. Some of these are live regions (#95), and a region that is
   display: none until it speaks is one the screen reader never saw become
   live, so its first words go unread. Zero size, not display: none. */
.v-hint:empty { margin-block: 0; min-block-size: 0; }
/* The links step's refusal line sits last above the step presses (#437),
   so it keeps the rows' air under it, said or empty (#364). */
.v-link-rows ~ .v-hint--bad { margin-block-end: .9rem; }
.v-hint--ok  { color: var(--v-ok); }
.v-hint--bad { color: var(--v-danger); }
.v-hint--warn { color: var(--v-warn); }



/* The accessibility footer (#103): the icon that reveals the widget, and
   the two legal links under it. Erez's shape — the icon centred, the links
   a muted centred row beneath, separated by a dot. */

.v-a11y { text-align: center; padding-block: 1.5rem 1.25rem; }

.v-a11y-toggle {
  inline-size: 44px;
  block-size: 44px;
  border-radius: 50%;
  border: 2px solid var(--v-line);
  background: var(--v-surface);
  color: var(--v-accent);
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.v-a11y-toggle:hover { border-color: var(--v-accent); }

.v-a11y-legal-row {
  margin-block: .85rem 0;
  font-size: .85rem;
  /* The links wrap to a second line on a narrow phone rather than running
     off the edge; the dot wraps with them. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .5rem;
}
.v-a11y-legal { color: var(--v-ink-muted); text-decoration: none; }
.v-a11y-legal:hover { color: var(--v-ink); }
.v-a11y-dot { color: var(--v-ink-muted); }
/* The accessibility statement takes the line under the other two (#271,
   Adam's #253 hand test: three on one line crowd a phone). An empty item
   of no height takes the rest of the line before it, so the statement
   starts a line of its own and the row's centring puts it under them. The
   line belongs to the break and not to the link: a link carrying it would
   be a press the width of the footer, and a tap on the blank beside the
   words would open the statement (fresh reviewer, 2026-09-27). */
.v-a11y-line-break { flex-basis: 100%; block-size: 0; }

/* The side bar (#156, 3.6a) on the realtor's signed-in pages. On a wide
   screen a strip of icons at the start edge, widening over the page with
   the words under the pointer or the keyboard; the icons stay where they
   are as it widens, so a press aimed at one lands on it. The words are
   faded rather than removed, so a screen reader and the tab key still
   reach every entry, and the keyboard arriving is what widens it. On a
   phone it is hidden behind the menu icon and opens over the page. */

.v-side-bar-wrap { display: contents; }

.v-side-bar {
  position: fixed;
  inset-block: 0;
  inset-inline-start: 0;
  z-index: 20;
  inline-size: 3.5rem;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-block: .75rem;
  background: var(--v-surface);
  border-inline-end: 1px solid var(--v-line);
  transition: inline-size .19s ease;
}
/* The keyboard's focus widens it, a mouse press's does not: a press on an
   entry that keeps the page (a legal link's new tab) would otherwise hold
   it wide after the pointer left (stranger's pass, 2026-09-14). */
.v-side-bar:hover, .v-side-bar:has(:focus-visible) { inline-size: var(--v-side-bar-open, 17rem); box-shadow: var(--v-shadow); }
/* As wide as its longest line (Adam's hand test, 2026-09-14): the side bar's
   script measures the bar at its content's width, once, and hands it to the
   rules above as --v-side-bar-open. */
.v-side-bar.is-measuring { display: flex !important; inline-size: max-content !important; transition: none !important; }
.v-side-bar.is-measuring .v-a11y-legal-row { display: none !important; }

.v-side-bar-list { list-style: none; margin: 0; padding: 0; }
.v-side-bar-form { margin: 0; }

.v-side-bar-entry {
  display: flex;
  align-items: center;
  gap: .9rem;
  inline-size: 100%;
  min-block-size: 2.75rem;
  margin: 0;
  padding-block: .4rem;
  padding-inline: 1.1rem .75rem;
  border: 0;
  border-inline-start: 3px solid transparent;
  background: none;
  color: var(--v-ink);
  font: inherit;
  text-align: start;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.v-side-bar-entry i { flex: none; inline-size: 1.3rem; margin-inline-start: -3px; text-align: center; font-size: 1.15rem; color: var(--v-ink-muted); }
a.v-side-bar-entry:hover i, button.v-side-bar-entry:hover i { color: var(--v-accent); }
/* NadlanCard's brand on the home page's entry (#406, step 8): the home
   page header's badge, in the look's accent, in the icon's place. */
/* NadlanCard's mark (PR #481): the N in the ink, the roof in the accent,
   on the side bar's own ground; site_theme_contrast_test.rb weighs both. */
.v-side-bar-brand { flex: none; display: grid; place-items: center; inline-size: 1.6rem; block-size: 1.6rem; margin-inline-start: -.25rem; color: var(--v-ink); }
.v-side-bar-brand .nc-mark { inline-size: 100%; block-size: 100%; }
.v-side-bar-brand .nc-mark-roof { stroke: var(--v-accent); }
/* After the brand, a small grey "to the home page" (Adam), a fifth under .8rem
   and set off by a gap beyond the space (his hand test). */
.v-side-bar-home { font-size: .64rem; color: var(--v-ink-muted); margin-inline-start: .5em; }
/* The page the realtor is on: a tinted row with a blue edge, icon and word,
   visible on the collapsed strip too (Adam's hand test, 2026-09-14). */
.v-side-bar-entry[aria-current="page"] { border-inline-start-color: var(--v-accent); background: var(--v-accent-wash); }
.v-side-bar-entry[aria-current="page"], .v-side-bar-entry[aria-current="page"] i { color: var(--v-accent-on-wash); }
/* Grey lines between the rows, and one above the accessibility icon
   (Adam's hand test, 2026-09-14). */
.v-side-bar-list > li + li, .v-side-bar-form, .v-side-bar .v-a11y { border-block-start: 1px solid var(--v-divider); }
/* The language switch (#154): "Language:" and a flag per language on one
   line, the current flag ringed in blue. */
.v-side-bar-langs { cursor: default; }
/* The light and dark presses the look entry keeps for a browser without
   script (#187), side by side under it, the current one ringed. */
.v-side-bar-themes-row { display: flex; align-items: center; gap: .4rem; padding-inline: 1.1rem .75rem; padding-block-end: .4rem; }
.v-theme-choice-form { margin: 0; }
.v-theme-choice {
  padding: .4rem .45rem; font: inherit; font-size: .8rem; cursor: pointer;
  color: var(--v-ink); background: var(--v-page);
  border: 2px solid var(--v-line); border-radius: 10px;
}
.v-theme-choice[aria-current="true"] { border-color: var(--v-accent); }
/* The looks pop-up (#188): the card picker's list, without the card
   beside it. The list is the design step's own rule set (.v-look-set,
   .v-look-choice), so the two read as one thing. */
/* As wide as its two columns, never narrower than it was with one. */
.v-dialog.v-site-look { inline-size: fit-content; min-inline-size: min(24rem, 96vw); max-inline-size: 96vw; }
/* Light and dark carry a sun and a moon where a palette has its strip,
   each in its own tone whichever look is on. */
.v-site-look .v-look-choice i { font-size: 1.15rem; }
.v-site-look .fa-sun { color: var(--v-warn-strong); }
.v-site-look .fa-moon { color: var(--v-soft-ink); }
.v-site-look .v-look-set { margin-block: 1rem 1.25rem; }
.v-site-look .v-actions--dialog { margin: 0; justify-content: center; }
.v-side-bar-langs-row { display: flex; align-items: center; gap: .5rem; }
.v-lang-flag-form { margin: 0; }
.v-lang-flag { padding: .15rem .25rem; border: 2px solid transparent; border-radius: 4px; background: none; line-height: 0; cursor: pointer; }
.v-lang-flag[aria-current="true"] { border-color: var(--v-accent); }
/* The same flags in the corner above the sign-in box, for a visitor with
   no side bar yet (#181): at the end of the line, so the box's far corner. */
.v-lang-corner { display: flex; justify-content: flex-end; gap: .35rem; margin-block-end: .6rem; }
/* A thumb's worth of press on a phone (the stranger's pass): the ring
   grows with the padding, the flag does not. */
.v-lang-corner .v-lang-flag { padding: .7rem .6rem; }
/* The settings entry (#278) sits in the foot beside the sign-out form, so
   it takes the same line above it the form has. This is the one line
   between the list and the foot: the list used to close itself with a
   border of its own, which met this one as a 2px rule on a short phone
   (#278 round 3). The foot's first row draws it in every bar, with the
   settings entry or without it. */
.v-side-bar-foot > .v-side-bar-entry { border-block-start: 1px solid var(--v-divider); }
/* Sign out in red, icon and word (Adam's hand test, 2026-09-14). */
.v-side-bar-form--out .v-side-bar-entry, .v-side-bar-form--out .v-side-bar-entry i { color: var(--v-danger); }

/* The name wraps inside a fixed width, so the collapsed bar does not
   squeeze it into a letter per line. */
.v-side-bar-who { cursor: default; white-space: normal; font-size: .85rem; color: var(--v-ink-muted); }
.v-side-bar-who .v-side-bar-label { flex: none; max-inline-size: 12.5rem; overflow-wrap: anywhere; }

/* The accessibility row: the icon centred on its own line, the legal links
   centred under it once the bar widens (Adam's hand test, 2026-09-14). The
   links keep one width while the bar widens, so they do not rewrap and
   push the icon up as it goes. */
.v-side-bar .v-a11y { display: flex; flex-direction: column; align-items: center; gap: .6rem; padding-block: 1rem 0; text-align: center; }
.v-side-bar .v-a11y-toggle { flex: none; }
.v-side-bar .v-a11y-legal-row { flex: none; inline-size: calc(var(--v-side-bar-open, 17rem) - 2rem); margin: 0; justify-content: center; gap: .15rem .4rem; font-size: .8rem; }

.v-side-bar-label, .v-side-bar .v-a11y-legal-row { opacity: 0; transition: opacity .19s ease; }
.v-side-bar:hover :is(.v-side-bar-label, .v-a11y-legal-row),
.v-side-bar:has(:focus-visible) :is(.v-side-bar-label, .v-a11y-legal-row) { opacity: 1; }

.v-side-bar-menu {
  position: fixed;
  inset-block-start: .5rem;
  inset-inline-start: .5rem;
  z-index: 21;
  display: none;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--v-line);
  border-radius: 50%;
  background: var(--v-surface);
  color: var(--v-ink);
  font-size: 1.15rem;
  cursor: pointer;
}

/* The home link at the top of a phone's screen, beside the menu icon (#325):
   the menu icon's height and edge, so the two read as one row. It scrolls
   away with the page rather than riding over the boxes as the round icon
   does; the menu still holds it. A wide screen has the bar's own entry in
   view and no need of it. */
.v-top-home {
  position: absolute;
  inset-block-start: 1.25rem;
  inset-inline-start: 3.75rem;
  z-index: 19;
  display: none;
  align-items: center;
  gap: .5rem;
  min-block-size: 2.75rem;
  padding-inline: 1rem;
  border: 1px solid var(--v-line);
  border-radius: 999px;
  background: var(--v-surface);
  color: var(--v-ink);
  text-decoration: none;
  white-space: nowrap;
}
.v-top-home i { color: var(--v-accent); }
.v-top-home:hover { border-color: var(--v-accent); }

@media (min-width: 40rem) {
  body.v-has-side-bar { padding-inline-start: 5.5rem; }
}

@media (max-width: 39.99rem) {
  /* A little below the top, and the open bar a third narrower than first
     built (Adam's hand test, 2026-09-14); the name and the legal links
     wrap to fit it. */
  .v-side-bar-menu { display: inline-flex; inset-block-start: 1.25rem; }
  .v-top-home { display: inline-flex; }
  .v-side-bar { display: none; padding-block-start: 4.5rem; }
  .v-side-bar, .v-side-bar:hover, .v-side-bar:has(:focus-visible) { inline-size: min(var(--v-side-bar-open, 12rem), 85vw); transition: none; }
  /* The open bar's words, on a phone only: a phone turned wide with the
     menu open is the plain strip (stranger's pass, 2026-09-14). */
  .v-side-bar.is-open :is(.v-side-bar-label, .v-a11y-legal-row) { opacity: 1; }
  /* The page starts under the menu icon, not beneath it. */
  body.v-has-side-bar .v-shell { padding-block-start: 4.75rem; }
  .v-side-bar-who .v-side-bar-label { max-inline-size: 8rem; }
  .v-side-bar .v-a11y-legal-row { inline-size: 100%; }
  .v-side-bar.is-open { display: flex; box-shadow: 0 0 0 100vmax rgb(0 0 0 / .6); }
  /* The page under the open bar stays put (Adam's hand test, 2026-09-14). */
  html.v-side-bar-locked { overflow: hidden; }
}

@media (prefers-reduced-motion: reduce) {
  .v-side-bar, .v-side-bar-label, .v-side-bar .v-a11y-legal-row { transition: none; }
  .v-admin-chevron, .v-admin-history-chevron { transition: none; }
}

/* The admin screens (#250, reshaped 2026-09-23 on Adam's look): each
   account or card is one closed entry, boxed like the realtor's own card
   rows, that opens on a press to the act and to a folded history. The
   closed entry is a table row in all but markup — one line, the width of
   the list, its facts divided by a rule and standing under the header's
   own names. On a phone it stacks instead, and the header goes. */
.v-shell--admin { max-inline-size: 46rem; }
/* A desktop gives the one-line rows room for their facts (#385, Adam after
   the first deploy). */
@media (min-width: 64rem) { .v-shell--admin { max-inline-size: 80rem; } }
.v-admin-nav { display: flex; flex-wrap: wrap; gap: .5rem; margin-block-end: 1.25rem; }
.v-admin-search { display: flex; flex-wrap: wrap; align-items: end; gap: .5rem; margin-block-end: 1.5rem; }
.v-admin-search .v-label { margin-block-end: .35rem; flex-basis: 100%; }
.v-admin-search .v-input { flex: 1 1 12rem; min-inline-size: 0; }
/* How big the whole result is, beside the box that narrowed it (#258). */
.v-admin-count { margin: 0; align-self: center; font-size: .85rem; color: var(--v-ink-muted); }
.v-admin-more { margin: .9rem 0 0; text-align: center; }
/* The consent list's own press (#253), under the search box: a press in a
   form of its own, so it carries the space down to the list itself. */
.v-admin-download { margin-block-end: 1.5rem; }
/* The way to the download log (#253 round 2), at the top-left corner of the
   search box. The margins are physical on purpose: Adam asked for the same
   corner in Hebrew as in English, and `margin-inline-end: auto` would put it
   under the start of the Hebrew text instead. */
.v-admin-log-link { inline-size: fit-content; margin: 0 auto .6rem 0; }
/* The log itself: one line per download, no fold, since a row here has nothing
   to open. On a phone the three facts stack. */
.v-admin-log { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.v-admin-log-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .75rem;
  padding: .7rem .85rem; border: 1px solid var(--v-line); border-radius: var(--v-radius); }
.v-admin-log-who { font-weight: 600; direction: ltr; unicode-bidi: isolate; }
.v-admin-log-when { color: var(--v-ink-muted); font-size: .85rem; }
.v-admin-log-count { color: var(--v-ink-muted); font-size: .9rem; }
/* How long the queue is, on a screen with no search box beside it (#251). */
.v-admin-count--alone { margin-block-end: 1rem; }
/* The language links (#166): five small presses on one row, each a filter of
   the cards list. They wrap on a phone rather than scrolling sideways, and
   the row keeps the count line's own space below it. */
.v-admin-languages { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; align-self: stretch; }

/* One track list per screen, named once and used by the header and by
   every row, so a column name cannot stand over the wrong fact (Adam,
   2026-09-23, on a screenshot where the two were one column apart). The
   first column is the flexible one — the email, the card address — and
   every other is fixed at the width of its longest value in either
   language. The last track is the chevron's, and the header counts it
   with an empty cell of its own. */
.v-admin-list--accounts, .v-admin-head--accounts { --v-admin-cols: minmax(0, 1fr) 9rem 5rem 5rem; }
.v-admin-list--cards, .v-admin-head--cards { --v-admin-cols: minmax(0, 1fr) 6.5rem 10.5rem 6rem 4.5rem; }
/* The review queue (#251): the address it signed up with, the day it did,
   and its cards. The cards share the flexible width with the email, since
   both are addresses and either can be the long one. */
.v-admin-list--reviews, .v-admin-head--reviews { --v-admin-cols: minmax(0, 1fr) 9rem minmax(0, 1fr); }
/* One card, one line: the address at the start of the line and whatever the
   card says about itself at the far end, hard against the chevron's track
   (#251 round 5). The pill is taller than the words beside it, so the
   line's height comes from it (#258 round 8, the same lesson).

   The value box is a block at every width, against the inline-block every
   other value is: a line whose end is the cell's end has to know where the
   cell ends. It clips nothing — the address inside it carries the ellipsis
   — so the pills are drawn whole. */
.v-admin-list--reviews .v-admin-cell--cards .v-admin-value { display: block; overflow: visible; }
.v-admin-card { display: flex; align-items: center; gap: .35rem; min-inline-size: 0; }
.v-admin-card .v-admin-address {
  min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The end slot. `auto` rather than `space-between`, so a card with nothing
   to say about itself still leaves its address at the start. */
.v-admin-card-state {
  margin-inline-start: auto; display: inline-flex; align-items: center; gap: .35rem; flex: none;
}
.v-admin-head { display: none; font-size: .8rem; font-weight: 500; color: var(--v-ink-muted); }
.v-admin-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.v-admin-entry { border: 1px solid var(--v-line); border-radius: var(--v-radius); background: var(--v-surface); }
.v-admin-entry--blocked { background: var(--v-danger-bg); border-color: var(--v-danger-line); }
.v-admin-entry--hidden { background: var(--v-warn-bg); border-color: var(--v-warn-line); }
/* A deleted card's trail (#333): dashed, as a card that is no longer there. */
.v-admin-entry--gone { border-style: dashed; }
.v-admin-summary { list-style: none; cursor: pointer; }
.v-admin-summary::-webkit-details-marker { display: none; }
.v-admin-summary:focus-visible { outline: 3px solid var(--v-accent); outline-offset: -3px; }
.v-admin-cell { min-inline-size: 0; font-size: .9rem; color: var(--v-ink-muted); }
.v-admin-value { overflow-wrap: anywhere; }
/* The facts read at a glance by colour, and every word under the colour
   says the same thing, so nothing rests on telling red from green (#258).
   All three pass AA on the row's own surface and on the red and amber
   washes, in both palettes. */
.v-admin-value--accent { color: var(--v-accent); }
.v-admin-value--ok { color: var(--v-ok-soft); }
.v-admin-value--bad { color: var(--v-danger); }
/* A press that copies the address it shows (#258), standing in the opened
   entry since #90 rather than inside the summary that opens it. A button
   with nothing of a button about it but the press: the colour and the
   underline say it is one, and the focus ring is the site's own. */
.v-admin-copy {
  font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0;
  cursor: pointer; text-align: inherit; max-inline-size: 100%;
}
.v-admin-copy:hover .v-admin-value, .v-admin-copy:focus-visible .v-admin-value { text-decoration: underline; }
.v-admin-copy:focus-visible { outline: 3px solid var(--v-accent); outline-offset: 2px; border-radius: 4px; }
/* "Copied", over the end of the box it belongs to for a moment, so nothing
   grows and nothing is pushed out of the way. */
.v-admin-box { position: relative; max-inline-size: 100%; }
.v-admin-copied:not(:empty) {
  position: absolute; inset-block-start: 50%; inset-inline-end: 0; transform: translateY(-50%);
  font-size: .8rem; color: var(--v-ok-soft); background: var(--v-ok-bg);
  border: 1px solid var(--v-ok-line); border-radius: 999px; padding: .1rem .5rem;
}
/* What an entry's addresses can be done with, on one line at the top of the
   opened body (#90): the copy press, and each card's page. The line has the
   width of the body rather than of a cell, so "Copied" stands beside the
   address instead of over the end of it. */
.v-admin-reach { margin: 0; display: flex; align-items: center; flex-wrap: wrap; gap: .5rem .9rem; }
.v-admin-copy-row { display: inline-flex; align-items: center; gap: .5rem; }
.v-admin-copy-row .v-admin-copied:not(:empty) { position: static; transform: none; }
.v-admin-chevron { color: var(--v-ink-muted); transition: transform .15s; }
/* The icon alone turns; its box never moves, so a press does not shift
   the row under the pointer (Adam saw it jump, 2026-09-23). */
.v-admin-fold[open] > .v-admin-summary .v-admin-chevron { transform: rotate(180deg); }

/* The phone: the name of the entry on its own line with the chevron at the
   inline end of it, and then one fact per line under it (Adam, 2026-09-23,
   against letting three labelled facts spill over two lines). Each line is
   "label: value" on a two-column grid, so every label lines up and every
   value starts at the same place. */
.v-admin-summary {
  display: grid; grid-template-columns: minmax(0, 1fr) 1.5rem;
  align-items: center; gap: .35rem .75rem;
  padding: .75rem .9rem; border-radius: var(--v-radius);
}
.v-admin-summary > .v-admin-cell:first-child { grid-area: 1 / 1; }
.v-admin-chevron { grid-area: 1 / 2; justify-self: end; }
.v-admin-facts {
  grid-area: 2 / 1 / auto / -1;
  display: grid; grid-template-columns: max-content minmax(0, 1fr);
  column-gap: .75rem; row-gap: .25rem; min-inline-size: 0;
  margin-block-start: .5rem; padding-block-start: .5rem;
  border-block-start: 1px solid var(--v-line);
}
/* The cell's own box steps aside so its label and its value are the two
   columns of that grid. Both stay exactly one child each way. */
.v-admin-facts > .v-admin-cell { display: contents; }
.v-admin-label { font-size: .8rem; }
@media (max-width: 39.999rem) {
  /* The label is read aloud everywhere and drawn here, where the column it
     names is gone. Every property `.v-sr-only` hides it with is undone. */
  .v-admin-label {
    position: static; inline-size: auto; block-size: auto; margin: 0;
    overflow: visible; clip-path: none; white-space: normal;
  }
}

@media (min-width: 40rem) {
  .v-admin-head { display: grid; }
  /* The header and the row are one grid: the same tracks, the same gap and
     the same inline padding, taken from one custom property and one shared
     selector, so a change to either cannot leave the other behind. */
  .v-admin-head, .v-admin-summary { grid-template-columns: var(--v-admin-cols) 1.5rem; gap: 0; }
  .v-admin-head { padding-block: 0 .35rem; padding-inline: .9rem; }
  /* `display: contents` so the facts are cells of that one grid here, and
     a line of their own only on a phone. */
  .v-admin-facts { display: contents; }
  .v-admin-facts > .v-admin-cell { display: block; }
  .v-admin-summary > .v-admin-cell:first-child, .v-admin-chevron { grid-area: auto; }
  /* One line each: a fixed cell never wraps, and the flexible one is cut
     with an ellipsis rather than wrapped mid-word. Its whole value is in
     the cell's `title` and read out in full to a screen reader. */
  .v-admin-cell, .v-admin-head > span { padding-inline: .75rem; white-space: nowrap; }
  /* The ellipsis lives on the value, not on the cell: a cell that clips
     would cut the bottom off the state pill, which is taller than a line
     of text (Adam's screenshot, 2026-09-23). */
  .v-admin-head > span, .v-admin-value {
    display: inline-block; max-inline-size: 100%; vertical-align: middle;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* An address reads from its start, so it is cut at its end. Shrink to
     fit, so a short one still sits at the row's own start. */
  .v-admin-value--ltr { direction: ltr; text-align: start; }
  /* A pill is taller than the line of text beside it: an inline box's
     padding and border do not count towards the line, so the value box
     came out one text line tall and cut the pill's border off, top and
     bottom (Adam, 2026-09-23). As an inline-block the pill sizes the line
     itself, and the value holding it has nothing to ellipsise, so it does
     not clip. `.v-state` is untouched where the realtor's own account
     page uses it. */
  .v-admin-value .v-state { display: inline-block; vertical-align: middle; }
  /* The cells that hold a pill do not clip: only the ones that ellipsise an
     address need to. The queue's cards cell says so for every width, above. */
  .v-admin-cell--state .v-admin-value { overflow: visible; }
  .v-admin-cell:first-child, .v-admin-head > span:first-child { padding-inline-start: 0; }
  /* A rule between every two facts, clear of the text either side of it. */
  .v-admin-cell + .v-admin-cell, .v-admin-facts > .v-admin-cell:first-child {
    border-inline-start: 1px solid var(--v-line);
  }
  .v-admin-value { overflow-wrap: normal; }
  /* The tallest cell sets the row's height, the pill included. */
  .v-admin-summary { align-items: center; }
}
.v-admin-body { padding-block: .9rem; padding-inline: .9rem; border-block-start: 1px solid var(--v-line); }
.v-admin-email { overflow-wrap: anywhere; }
.v-admin-address { overflow-wrap: anywhere; }
.v-admin-act { display: flex; flex-wrap: wrap; align-items: end; gap: .5rem; }
/* One row of the review queue holds three presses, one under the next, and
   the one that needs no reason has no field to stand beside (#251). */
.v-admin-body > .v-admin-act:not(:first-child), .v-admin-act + .v-field-error {
  margin-block-start: .75rem;
}
/* A card's open row is a button row first (#252 round 2): up to three
   presses side by side, each in its own colour, and under them the reason
   box of whichever one was pressed. The buttons wrap on a phone rather
   than squeezing, so each keeps a pressable width.

   The colours are the palette's own inks on the row's surface. Every one
   of them clears WCAG AA on white and on the amber wash of a hidden row,
   in light and in dark; the tightest is --v-danger on --v-warn-bg in
   light, at 5.97:1. */
.v-admin-press-row { display: flex; flex-wrap: wrap; gap: .5rem; }
.v-admin-box { margin-block-start: .9rem; }
.v-admin-act-field { flex: 1 1 14rem; min-inline-size: 0; }
.v-admin-act .v-input { inline-size: 100%; }
.v-admin-reason-label { display: block; margin-block-end: .35rem; }
/* The history folds under the act; each entry of it is boxed on its own. */
.v-admin-history { margin-block-start: .9rem; }
.v-admin-history-title {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: .4rem;
  font-size: .85rem; font-weight: 500; color: var(--v-accent);
}
.v-admin-history-title::-webkit-details-marker { display: none; }
.v-admin-history-title:focus-visible { outline: 3px solid var(--v-accent); outline-offset: 2px; }
.v-admin-history-chevron { font-size: .7rem; transition: transform .15s; }
.v-admin-history[open] > .v-admin-history-title .v-admin-history-chevron { transform: rotate(180deg); }
.v-admin-history-empty { font-size: .8rem; margin: .5rem 0 0; }
.v-admin-history-list { list-style: none; margin: .5rem 0 0; padding: 0; display: grid; gap: .4rem; font-size: .8rem; }
.v-admin-history-list li {
  display: flex; flex-wrap: wrap; gap: .3rem .5rem;
  padding: .5rem .7rem; border: 1px solid var(--v-line); border-radius: calc(var(--v-radius) / 2);
  background: color-mix(in srgb, var(--v-ink) 4%, transparent);
}
.v-admin-history-act { font-weight: 600; }
.v-admin-history-who, .v-admin-history-list time { color: var(--v-ink-muted); }
.v-admin-history-reason { flex-basis: 100%; overflow-wrap: anywhere; }
/* The presses for one row's history (#272): the next batch, and the way back
   to the first three (round 2). Under the lines they change, side by side,
   and inside the fold they belong to. */
.v-admin-history-presses { margin: .6rem 0 0; display: flex; gap: .5rem; flex-wrap: wrap; }

/* Hidden by admin, on the realtor's own card row (#250). Amber, like every
   other "off the air" line on these screens, and the words carry it. */
.v-your-card-hidden {
  margin: .4rem 0 0;
  padding: .45rem var(--v-card-pad);
  font-size: .85rem;
  color: var(--v-warn-soft);
  background: var(--v-warn-bg);
  border: 1px solid var(--v-warn-line);
  border-radius: var(--v-radius);
}

/* The settings page (#278): the realtor's marketing agreement, the line
   that says where it stands and the words the agreeing press is about.
   The box's words are quoted rather than stated, so a realtor reads what
   they are agreeing to and not our summary of it. */
.v-consent { margin-block-start: 1rem; }
.v-consent-line { margin-block: 0 1rem; }
.v-consent-box {
  margin-block: 0 1rem;
  padding: .7rem .9rem;
  color: var(--v-ink-muted);
  background: var(--v-page);
  border: 1px solid var(--v-line);
  border-radius: var(--v-radius);
}
.v-consent .v-actions { margin-block: 0; }
/* After a withdrawal the page is two boxes (#278 round 5, Adam's look): the
   state in the first, the words to agree to and the press in the second.
   Same width and the same inner padding, since both are .v-card; one
   spacing step between them, which is the gap the shell has nowhere else. */
.v-consent-agree, .v-account-email { margin-block-start: 1rem; }
.v-consent-agree .v-consent-box { margin-block: 0 1rem; }
.v-consent-agree .v-actions { margin-block: 0; }

/* An admin acting as a realtor (#467): a strip across the top of every
   screen, in colours of its own that no palette and no look moves.
   Near-black on amber, checked in test/assets/acting_banner_contrast_test.rb.
   Above the side bar's strip, so the exit is never under it. */
.v-acting {
  position: relative;
  z-index: 21;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem 1rem;
  padding: .625rem 1rem;
  background: var(--v-acting-bg);
  color: var(--v-acting-ink);
  font-weight: 600;
}
.v-acting-line { margin: 0; overflow-wrap: anywhere; }
.v-acting-form { margin: 0; }
.v-acting-exit {
  min-block-size: 2.75rem;
  padding: .375rem 1rem;
  border: 2px solid var(--v-acting-ink);
  border-radius: var(--v-radius);
  background: var(--v-acting-ink);
  color: var(--v-acting-on-ink);
  font: inherit;
  cursor: pointer;
}
.v-acting-exit:focus-visible { outline: 3px solid var(--v-acting-ink); outline-offset: 2px; }

/* The one-time marketing ask (#467 review): the site's dialog, its box
   above the two presses; each press sits in a form of its own, and the
   forms step aside so the presses share the dialog's row. */
.v-consent-reask .v-consent-box { margin-block: 1rem; }
.v-consent-reask .v-consent-box bdi { overflow-wrap: anywhere; }
.v-consent-reask-form { display: contents; }

/* On a phone the menu icon stands at the top start corner of a page with
   the side bar; the strip's words start after it. */
@media (max-width: 39.99rem) {
  .v-has-side-bar .v-acting { padding-inline-start: 4.5rem; }
}

/* The AI help page (#473): Erez's VibeInbox template in the screens' own
   tokens, against its purple. The badge and the pills take the accent's
   wash, the steps the tray, and the press is the primary press at full
   width; no colour of its own. */
/* The heading sits in a centred row with the small way home (Adam's hand
   test of PR 2): the row, not the heading, keeps the room under it. */
.v-ai-help .v-title-row--centred { margin-block-end: 1.25rem; }
.v-ai-help .v-title-row--centred .v-title { margin-block-end: 0; }
.v-ai-help h2 { font-size: 1.05rem; margin: 0; }
.v-ai-help-head { display: flex; align-items: center; gap: .85rem; margin-block-end: 1rem; }
.v-ai-help-head p { margin: 0; color: var(--v-ink-muted); font-size: .9rem; }
.v-ai-help-badge {
  display: grid; place-items: center; flex: none;
  inline-size: 2.75rem; block-size: 2.75rem; border-radius: 12px;
  background: var(--v-accent-wash); color: var(--v-accent-on-wash); font-size: 1.25rem;
}
.v-ai-help-intro p { margin-block: 0 .5rem; }
.v-ai-help-models-label { margin-block: 1rem .5rem; font-size: .85rem; font-weight: 600; color: var(--v-ink-muted); }
.v-ai-help-models { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0 0 1.25rem; padding: 0; list-style: none; }
.v-ai-help-models li {
  padding: .3rem .8rem; border: 1px solid var(--v-accent-line); border-radius: 999px;
  background: var(--v-accent-wash); color: var(--v-accent-on-wash); font-size: .85rem; font-weight: 600;
}
.v-ai-help-steps { padding: 1rem 1.15rem; border-radius: var(--v-radius); background: var(--v-tray); }
.v-ai-help-steps ol { margin: .5rem 0 0; padding-inline-start: 1.4rem; }
.v-ai-help-steps li + li { margin-block-start: .35rem; }
.v-btn.v-ai-help-download { display: flex; justify-content: center; inline-size: 100%; margin-block-start: 1.25rem; }
.v-ai-help-note { margin-block-start: .6rem; font-size: .85rem; text-align: center; }
