/* =============================================
   IGA — matched to the association's public website.

   This is not a house style of ours any more; it tracks iga.org.il so a
   member moving from the site into the certificate system does not feel
   they went anywhere. Green on white, near-black ink, 1px hairlines,
   zero border-radius, Heebo for Hebrew and Latin, JetBrains Mono for data.

   THE GREENS ARE TWO, AND THE SPLIT IS DELIBERATE.
   ⚠ THE INK IS THE COLLEGE'S NAVY, #082646 — 15.26:1 against white, measured
   off carcollege.co.il on 15.9.2026. It replaced the association's own #032553
   (Ronen, 2026-08-12, 15.07:1), which had replaced the green this paragraph
   used to describe. The app moved with the public site rather than apart from
   it; tests/test_review_fixes.py::test_the_two_products_are_one_product is the
   reason, and it is the rule that made the decision, not a preference.

   The green needed two values and this does not. #0E9E62 measured 3.45:1: it
   cleared the 3:1 WCAG 1.4.11 asks of a non-text component and missed the
   4.5:1 it asks of text, so a second, darker green had to carry every label
   and every white-on-fill button. One navy now carries edges, fills and text
   alike, and the public site and the certificates app hold the same value
   rather than a documented exception between them.

   Comments further down still describe the old green where they explain a
   layout decision that has not changed; the colour they name has.
*/

:root {
  color-scheme: light;

  /* Ink — the college's navy, and the dark surfaces built from it.
     ⚠ MOVED OFF THE NEAR-BLACK GREEN 15.9.2026, AND THE APP MOVED WITH THE
     SITE ON PURPOSE. tests/test_review_fixes.py::test_the_two_products_are_one
     _product exists to stop these drifting: a member who follows «אימות אישור»
     out of the public site into the certificate screens must not feel they
     left. When the public site took the college's design the choice was to move
     both or to grow a second documented exception, and Rami took the first.
     Measured: 15.26:1 on white, 14.06:1 on the grey band. */
  --ink: #082646;
  --ink-2: #0b3059;   /* the site's hero stripe */
  --ink-3: #1a3f68;   /* hover on a dark surface */
  --ink-4: #24456b;   /* the site's body-2, dark enough to serve as a border */

  /* Paper — the site is white, with one grey band */
  --bg: #ffffff;
  --bg-elevated: #f4f6f5;
  --card: #ffffff;

  /* Text. The site's #6B7A77 measures 4.14:1 on the grey band and #8A9895
     measures 3.00:1 on white; both are used for real copy, so both are
     darkened here to the nearest value that clears the line. */
  --text: #082646;             /* 15.26 / 14.06 */
  --text-secondary: #24456b;   /*  9.82 /  9.05 */
  --text-muted: #4d6a85;       /*  5.65 /  5.21 (AA) */
  --text-faint: #6b8299;       /*  3.98 /  3.67 — clearly 'inactive', still visible */

  /* Hairlines — the site draws every border as ink at low alpha. Flattened
     to hex so they do not double up where two bordered boxes touch. */
  --border-hairline: #e4e5e5;  /* rgba(11,18,17,.11) */
  --border: #dfe0e0;           /* rgba(11,18,17,.13) */
  --border-strong: #ced0cf;    /* rgba(11,18,17,.20) */

  /* The college's navy, #082646 — see the ink note above. There is no longer a
     "readable one" and a "brand one": the green needed two values because
     #0E9E62 is 3.45:1 on white and failed as text, and this measures 15.26:1,
     so one colour carries edges, fills and text alike. */
  --primary: #082646;          /* the college's navy — see the ink note above */
  --primary-dark: #05192f;     /* hover */
  --primary-edge: #24456b;     /* edges, dots, rules */
  --primary-bright: #8ed1fc;   /* on dark surfaces ONLY — 1.30:1 on white */
  --primary-light: rgba(8, 38, 70, 0.10);
  --primary-tint: rgba(8, 38, 70, 0.055);
  --signal-ink: #082646;
  --navy: #082646;
  --navy-2: #0b3059;
  --cyan: #0e9e62;

  /* Semantic — the site's, darkened where they carry text. Never the sole
     carrier of meaning. */
  --red: #c4342e;         --red-light: rgba(196, 52, 46, 0.09);
  --amber: #8a5a00;       --amber-light: rgba(181, 114, 0, 0.11);
  --amber-edge: #b57200;
  --blue: #2f5dbf;        --blue-light: rgba(47, 93, 191, 0.09);
  --emerald: #0a7c4c;     --emerald-light: rgba(14, 158, 98, 0.10);

  /* The site is flat except for one lift: a card raises on hover. */
  --shadow: none;
  --shadow-md: none;
  --shadow-lg: 0 14px 34px rgba(11, 18, 17, 0.09);

  /* Geometry — square. These stay at 0 on purpose; do not "restore" them. */
  --radius-sm: 0;
  --radius: 0;
  --radius-lg: 0;

  --font-sans: "Heebo", -apple-system, "Segoe UI", Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, Menlo, SFMono-Regular, monospace;

  /* Matched to .pub-sec / .pub-head: content centred at 1240, chrome inset
     by 2rem and otherwise full width. */
  --measure: 1240px;
  --gutter: 2rem;

  --ease-out: cubic-bezier(0.22, 0.95, 0.32, 1);
  --dur-fast: 120ms;
  --dur: 180ms;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }
html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  line-height: 1.6;
  letter-spacing: -0.004em;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* On dark surfaces the ink ring is invisible against its own background
   (1.08:1). The landing page's verify form is the primary CTA — it must show
   focus. */
.hero-tech :focus-visible,
.verify-panel :focus-visible,
.bot-head :focus-visible,
.verdict-valid :focus-visible { outline-color: var(--bg-elevated); }
/* The site's links are green and turn ink on hover. */
a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
::selection { background: var(--primary-edge); color: #fff; }

/* Every one of these carries a Latin/numeric run inside Hebrew prose, so they
   all need isolation — not just `code`. `.mono` used to be excluded, and
   templates compensated by hand: some added dir="ltr", some forgot, and the
   forgotten ones rendered allocation numbers and garage numbers reordered. */
.mono, .num-cell, code {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  direction: ltr;
  unicode-bidi: isolate;
}

/* ---------- chrome ----------
   Copied from the association's site so the two read as one product: a dark
   status strip, then a white sticky header that blurs what scrolls under it.
   Everything inside shares one measure with the page content below. */
/* The public site's chrome is FULL-BLEED with a 2rem inset (.pub-head,
   .pub-status), and only its sections are centred at 1240px. That is a
   different choice from the design export, which measured both at 1320 — but
   the site is what a member actually scrolls up from, so the app follows the
   site. Chrome full-bleed, content 1240: the same two rhythms, in the same
   order, so the header does not jump when they cross over. */
.shell { inline-size: 100%; padding-inline: var(--gutter); }

.statusbar { background: var(--ink); color: var(--text-faint); font-size: 11px; letter-spacing: .04em; }
.statusbar .shell {
  display: flex; align-items: center;
  gap: .4rem 1.5rem; flex-wrap: wrap; padding-block: .55rem;
}
/* The site's strip opens with a PULSING dot next to "all services
   operational". The mark is kept for the rhythm and the pulse is not: we
   monitor nothing, and a blinking green dot is read as an uptime claim. */
.statusbar .sys { display: flex; align-items: center; gap: .45rem; color: #fff; font-weight: 700; }
.statusbar .sys::before {
  content: ""; inline-size: 6px; block-size: 6px; flex: none;
  background: var(--primary-bright);
}
.statusbar .rule { inline-size: 1px; block-size: 13px; background: rgba(255, 255, 255, .22); }
.statusbar .spacer { flex: 1; }

.topbar {
  background: rgba(255, 255, 255, .94);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border-block-end: 1px solid var(--border);
  position: sticky;
  inset-block-start: 0;
  z-index: 60;
}
.topbar .shell {
  display: flex; align-items: center;
  gap: .8rem 2rem; flex-wrap: wrap; padding-block: 1rem;
  /* .pub-head measures 76px; pinned so the header does not shift by four
     pixels at the moment a member crosses from the site into the system. */
  min-block-size: 76px;
}
.brand { display: flex; align-items: center; gap: .75rem; color: var(--text); flex: none; }
.brand:hover { text-decoration: none; color: var(--text); }
.brand svg { inline-size: 38px; block-size: 38px; flex: none; }
.brand-text { display: flex; flex-direction: column; line-height: 1.15; min-inline-size: 0; }
.brand-main { font-weight: 800; font-size: 15px; letter-spacing: -0.02em; }
/* .pub-wordmark small — mono, 9.5px, tracked to .18em. A plate, not a sentence. */
.brand-sub { font-size: 9.5px; color: var(--text-muted); letter-spacing: .18em; }

/* .pub-nav: plain links, 13.5px/600, ink-secondary turning green. Not the
   padded button blocks of the design export — the site did not use those. */
.nav { display: flex; align-items: center; gap: 1.6rem; flex-wrap: wrap; min-inline-size: 0; margin-inline: auto; }
.nav a {
  color: var(--text-secondary); font-size: 13.5px; font-weight: 600;
  letter-spacing: -.014em; white-space: nowrap;
  background: none; border: 0; cursor: pointer; font-family: inherit;
  transition: color var(--dur) var(--ease-out);
}
.nav a:hover { color: var(--primary); text-decoration: none; }
/* The site marks the current page by colour alone. Colour alone is not a
   state indicator, so the current page also carries a rule under it —
   aria-current already says it, this makes it visible. */
.nav a.active { color: var(--primary); box-shadow: 0 2px 0 var(--primary-edge); }

/* The far-side actions: the site puts an outlined button and a filled green
   one here, and they stay pinned to the end however the nav wraps. */
.topbar-actions { display: flex; align-items: center; gap: .6rem; flex: none; }
.nav .btn-login, .topbar-actions .btn-login {
  border: 1px solid var(--border-strong); background: var(--card); color: var(--text);
  font-weight: 700; padding-block: .65rem; padding-inline: 1rem; font-size: .88rem;
}
.nav .btn-login:hover, .topbar-actions .btn-login:hover {
  border-color: var(--primary-edge); color: var(--primary); background: var(--card); text-decoration: none;
}

/* ---------- page & footer ---------- */
.page { flex: 1; inline-size: 100%; max-inline-size: var(--measure); margin-inline: auto; padding-inline: var(--gutter); padding-block: 2.4rem 3.5rem; }
/* 1320px is the site's measure, and it is right for its card grids. Running
   prose that wide is not readable, so paragraphs and lists inside a card are
   held to a sane line while tables and grids keep the full width.
   .notice is excluded: it is written as a <p> but it is a component, not
   prose, and capping it rendered every notice on the page as a floating
   two-thirds-width box instead of a full-width bar. */
.card > p:not(.notice), .card > ul, .card > ol, .page > p:not(.notice) { max-inline-size: 78ch; }
/* The site closes on a grey band with the mark and the association's name.
   Its five columns of site links are not reproduced — we would be inventing
   navigation that does not exist here — but the band and the mark are what
   make the bottom of the page look like the same product. */
.footer {
  background: var(--bg-elevated);
  border-block-start: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: .84rem;
}
.footer .shell {
  display: flex; align-items: center; gap: .6rem 1.2rem;
  flex-wrap: wrap; padding-block: 1.7rem;
}
.footer-brand { display: flex; align-items: center; gap: .65rem; font-weight: 800; color: var(--text); flex: none; }
.footer-brand svg { inline-size: 32px; block-size: 32px; flex: none; }

/* ---------- typography ----------
   The site's headings are 900 with the tracking pulled in hard; that weight
   and that negative tracking are what make it recognisable, more than the
   absolute size. Sizes stay app-scaled — a 62px h1 belongs on a hero. */
h1 { font-size: clamp(1.9rem, 3vw, 2.35rem); font-weight: 900; letter-spacing: -0.035em; line-height: 1.08; margin-block-end: 1.2rem; }
h2 { font-size: 1.15rem; font-weight: 800; letter-spacing: -0.025em; margin-block-end: .7rem; }
/* The site's section eyebrow: mono, small, tracked wide, green. */
.kicker {
  display: block; font-family: var(--font-mono); font-size: .68rem; font-weight: 600;
  letter-spacing: .16em; color: var(--primary); margin-block-end: .5rem;
  direction: ltr; unicode-bidi: isolate; text-align: start;
}
.muted { color: var(--text-muted); }
.small { font-size: .85rem; }

/* ---------- cards — square, hairline, flat ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  padding: 1.5rem 1.7rem;
  margin-block-end: 1rem;
}
/* The site's one piece of depth: a clickable card lifts and its edge goes
   green. Only cards that ARE links get it — a static panel that rises under
   the pointer is just noise. */
a.card, .card-link {
  display: block; color: inherit;
  transition: border-color var(--dur) var(--ease-out), transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}
a.card:hover, .card-link:hover {
  border-color: var(--primary-edge); transform: translateY(-3px);
  box-shadow: var(--shadow-lg); text-decoration: none; color: inherit;
}
@media (prefers-reduced-motion: reduce) {
  a.card:hover, .card-link:hover { transform: none; }
}
/* Grids share one hairline: the gap IS the rule. */
.grid { display: grid; gap: 1px; background: var(--border); border: 1px solid var(--border); }
.grid > * { background: var(--card); margin-block-end: 0; border: 0; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); }

/* ---------- stat tiles ---------- */
.stat { padding-block: 1.5rem; text-align: center; }
.stat .num {
  font-family: var(--font-mono); font-size: 2rem; font-weight: 600;
  color: var(--text); letter-spacing: -0.03em;
  direction: ltr; unicode-bidi: isolate;
}
.stat .lbl { color: var(--text-muted); font-size: .8rem; font-weight: 500; margin-block-start: .25rem; }
/* A low balance is the one number on this screen a garage must act on, so it
   does not rely on colour alone — the card is outlined, the figure is red, and
   the sentence under it says the amount in words. Colour-only state is the
   accessibility failure that a RED BALANCE would otherwise be. */
.stat-low { border-color: var(--red); background: var(--red-light); }
.stat-low .num { color: var(--red); }

/* ---------- buttons — square; weight carries hierarchy ----------
   The site's primary button is a green fill with a white label that turns
   ink on hover. Note the fill is --primary (#0a7c4c) and not the site's
   #0e9e62: white on #0e9e62 measures 3.45:1, and this label is 14–15px, so
   it does not reach the 3:1 large-text exemption either. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
  background: var(--primary); color: #fff; border: 1px solid var(--primary);
  padding-block: .7rem; padding-inline: 1.5rem;
  font: inherit; font-weight: 800; font-size: .95rem; cursor: pointer; text-decoration: none;
  transition: background var(--dur) var(--ease-out), color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.btn:hover { background: var(--ink); border-color: var(--ink); text-decoration: none; color: #fff; }
.btn-small { padding-block: .42rem; padding-inline: .95rem; font-size: .86rem; }
/* .btn-brand used to be ink, because the old accent was ochre and had to stay
   reserved. Green IS the brand now, so it is simply the primary button; the
   name survives so no template needed touching. */
.btn-brand { background: var(--primary); border-color: var(--primary); color: #fff; }
.btn-brand:hover { background: var(--ink); border-color: var(--ink); color: #fff; }
.btn-danger { background: var(--red); border-color: var(--red); color: #fff; }
.btn-danger:hover { background: #9e2823; border-color: #9e2823; color: #fff; }
.btn-outline {
  background: var(--card); color: var(--text); border-color: var(--border-strong);
}
.btn-outline:hover { background: var(--card); color: var(--primary); border-color: var(--primary-edge); }

/* ---------- forms ---------- */
label { display: block; font-size: .82rem; font-weight: 600; color: var(--text-secondary); margin-block-end: .35rem; }
input[type=text], input[type=password], input[type=email], input[type=tel], input[type=date],
input[type=number], select, textarea {
  inline-size: 100%; min-block-size: 2.9rem;
  padding-block: .55rem; padding-inline: .85rem;
  border: 1px solid var(--border-strong);
  font: inherit; font-size: .95rem; background: var(--card); color: var(--text);
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
input[type=date] { font-family: var(--font-mono); }
textarea { min-block-size: 4.6rem; }
/* The site marks focus by turning the field's edge green. One hairline is a
   thin indicator, so the inset doubles it to a visible 2px; #0e9e62 is 3.45:1
   on white, over the 3:1 WCAG 1.4.11 asks of a focus indicator. */
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--primary-edge);
  box-shadow: inset 0 0 0 1px var(--primary-edge);
}
input::placeholder { color: var(--text-faint); }
.field { margin-block-end: 1rem; }
/* Align to the START of the block, not the end. With `end`, any field whose
   help text runs longer than its neighbour's pushes its own label and control
   upwards, and a row of three fields renders as a staircase. Tops aligned means
   labels line up and controls line up; help text is free to hang below. */
form .row { display: grid; grid-template-columns: repeat(auto-fit, minmax(185px, 1fr)); gap: .85rem; align-items: start; }
/* A field and the button that acts on it, side by side. Deliberately NOT
   `.row`: that is an auto-fit grid of equal columns, which would have given a
   one-word «חפש» the same width as the search field beside it. Flex lets the
   input take the room and the button take only its content. min-inline-size:0
   because a flex item's automatic minimum is its content size — without it the
   input refuses to shrink and pushes the button off a narrow screen. */
form .row-tight { display: flex; gap: .5rem; align-items: start; }
form .row-tight > input { flex: 1 1 auto; min-inline-size: 0; }
form .row-tight > .btn { flex: 0 0 auto; white-space: nowrap; }
/* The signature-policy control on the admin dashboard: two fields and a button
   on one line, wrapping to their own lines on a narrow screen. baseline rather
   than start so the select, the text field and the button sit on the same line
   despite their different intrinsic heights. */
.policy-form { display: flex; flex-wrap: wrap; gap: .6rem; align-items: baseline; margin-block: .9rem; }
.policy-form label { margin-inline-end: -.2rem; }
.policy-form select, .policy-form input { min-inline-size: 0; }
.policy-form input { inline-size: 12ch; }
/* A control with no label of its own, sharing a row with labelled fields.
   Reserve exactly the block a label occupies (see the `label` rule above) so
   the controls sit on the same line instead of riding up to the row top. */
.field-nolabel { padding-block-start: calc(.82rem * 1.5 + .35rem); }
.field-nolabel > .chk { min-block-size: 2.9rem; }
.inline-form { display: inline; }

/* ---------- notices — a rule at the start, not a tinted pill ---------- */
.notice {
  display: flex; align-items: baseline; gap: .55rem;
  background: var(--card);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--ink);
  padding-block: .7rem; padding-inline: 1rem;
  margin-block: .8rem; font-size: .89rem; color: var(--text-secondary);
}
.notice::before { font-family: var(--font-mono); font-weight: 700; color: var(--text); }
.notice-ok { border-inline-start-color: var(--emerald); }
.notice-ok::before { content: "✓"; color: var(--emerald); }
.notice-warn { border-inline-start-color: var(--amber-edge); }
.notice-warn::before { content: "!"; color: var(--amber); }
.notice-err { border-inline-start-color: var(--red); }
.notice-err::before { content: "✕"; color: var(--red); }
.notice-info { border-inline-start-color: var(--border-strong); }
.notice-info::before { content: "i"; color: var(--text-muted); }

/* ---------- QR handoff to the phone ----------
   The signature gate offers the certificate to the manager's phone as a plain
   scannable link. qrcode's SvgPathImage carries its own width/height in mm,
   which renders enormous, so the size has to be taken back here. 180px is
   comfortably scannable at arm's length from a workshop monitor and still fits
   when the same page is opened on the phone itself. The white plate is not
   decoration: a QR inverted by a dark theme does not scan. */
.qr-block { margin-block: .9rem; }
.qr-block svg {
  inline-size: 180px; block-size: auto; max-inline-size: 100%;
  background: #fff; padding: .4rem; border: 1px solid var(--border);
}

/* ---------- verdicts ---------- */
.verdict {
  text-align: center; padding-block: 2.6rem;
  margin-block-end: 1rem; border: 1px solid var(--border);
  border-inline-start: 3px solid var(--ink);
  background: var(--card);
}
.verdict .big { font-size: 1.9rem; font-weight: 700; letter-spacing: -0.03em; }
.verdict .small { margin-block-start: .45rem; color: var(--text-muted); }
/* Valid gets the dark treatment — it is the answer the inspector is looking
   for, and it must read across a workshop at arm's length. */
.verdict-valid { background: var(--ink); color: var(--bg-elevated); border-color: var(--ink); border-inline-start-color: var(--primary-edge); }
.verdict-valid .small { color: var(--text-faint); }
.verdict-bad { border-inline-start-color: var(--red); color: var(--red); }
.verdict-bad .small { color: var(--text-muted); }
.verdict-warn { border-inline-start-color: var(--amber-edge); color: var(--amber); }
.verdict-warn .small { color: var(--text-muted); }

/* ---------- tables ---------- */
.tbl { inline-size: 100%; border-collapse: collapse; font-size: .89rem; background: var(--card); }
.tbl th, .tbl td {
  text-align: start; padding-block: .7rem; padding-inline: .9rem;
  border-block-end: 1px solid var(--border-hairline);
}
/* The site's column heads are mono and tracked out to .14em — but every one of
   them is a Latin word (ID, SUBJECT, VEHICLE, STATUS), and Hebrew does not take
   that treatment. Measured at .14em, "מספר רישוי" and "מפתח כניסה (Passkey)"
   render as loose separated letters and wrap to two lines inside their column.
   The tracking stays at .08em, for the same reason the row-header rule further
   down exists: this is a Hebrew table. */
.tbl th {
  font-family: var(--font-mono); color: var(--text-muted); font-weight: 600;
  font-size: .68rem; letter-spacing: .08em;
  border-block-end: 1px solid var(--ink);
}
.tbl tbody tr:hover { background: var(--primary-tint); }
.tbl tbody tr:last-child td { border-block-end: 0; }
/* Label/value tables — the certificate details on /verify, the estimate on
   /paint. These are not data grids, and stretched across the site's 1320px
   measure they park each value most of a screen from the label it belongs to,
   so the pair stops reading as one line. Cap the box they sit in.
   The `nowrap` label sizing is only for .detail-tbl: the estimate's row
   headers carry a wrapping basis line underneath, which nowrap would drag
   across the page. */
.tbl-wrap.narrow { max-inline-size: 44rem; }
.detail-tbl th[scope="row"] { inline-size: 1%; white-space: nowrap; }

.tbl-wrap { overflow-x: auto; border: 1px solid var(--border); background: var(--card); }
.num-cell { direction: ltr; unicode-bidi: isolate; text-align: start; font-size: .85rem; }
/* A date, a plate, an allocation number or a sum is ONE value. Wrapped, it
   reads as two — "2026-12" over "-14" — which is the house rule against cutting
   content in the middle, in its smallest form. The table scrolls instead:
   .tbl-wrap is overflow-x:auto, and a table that scrolls intact is the
   opposite of a value that has been cut. */
.tbl td.num-cell, .tbl th.num-cell { white-space: nowrap; }

/* ---------- chips — the site's status pill ----------
   The site draws these as a tinted block with no border: 11.5px, weight 800,
   3px/10px, colour + a 10% wash of itself. Adopted, with one addition kept
   from before: the leading shape. The site's pills carry their meaning in
   colour alone, and these get printed on paper and photocopied — a square, a
   bar and a struck line still read when the colour is gone. Colours are the
   site's, darkened where they sit on their own tint (see the top of file). */
.chip {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .72rem; font-weight: 800;
  padding-block: .2rem; padding-inline: .6rem;
  border: 0; color: var(--text-secondary); background: rgba(11, 18, 17, .06);
}
.chip::before { content: ""; inline-size: 7px; block-size: 7px; flex: none; background: currentColor; }
.chip-ok { color: var(--primary); background: var(--primary-light); }
.chip-warn { color: var(--amber); background: var(--amber-light); }
.chip-err { color: var(--red); background: var(--red-light); }
/* "cancelled" reads as a struck line even in greyscale or print */
.chip-err::before { background: none; border-block-start: 1px solid currentColor; block-size: 0; inline-size: 9px; }
.chip-info { color: var(--blue); background: var(--blue-light); }

/* ---------- dashboard marks ---------- */
.bars { display: flex; align-items: flex-end; gap: 2px; block-size: 128px; padding-block-start: .4rem; }
.bars .bar {
  flex: 1; background: var(--ink);
  min-block-size: 2px;
  transition: background var(--dur-fast) var(--ease-out);
}
.bars .bar:hover { background: var(--primary); }
.hbar { background: var(--border); block-size: 8px; overflow: hidden; }
.hbar > span { display: block; block-size: 100%; background: var(--ink); }

/* ---------- demo login box ---------- */
.demo-box {
  background: var(--bg-elevated); border: 1px dashed var(--border-strong);
  padding: 1.1rem 1.3rem; font-size: .87rem;
  color: var(--text-secondary);
}
.demo-box ul { list-style: none; margin-block: .6rem; display: grid; gap: .4rem; }
.demo-box code {
  background: var(--card); padding-block: .08rem; padding-inline: .45rem;
  border: 1px solid var(--border);
  font-size: .78rem;
}

/* ---------- OTP ---------- */
.otp-code {
  font-family: var(--font-mono); font-size: 2.3rem; font-weight: 600;
  letter-spacing: .35rem; text-align: center; direction: ltr; unicode-bidi: isolate;
  color: var(--primary-bright); background: var(--ink);
  padding-block: .85rem; margin-block: .8rem;
}

/* ---------- stepper ---------- */
.stepper { display: flex; gap: 1px; background: var(--border); border: 1px solid var(--border); margin-block-end: 1.3rem; flex-wrap: wrap; }
.step {
  flex: 1; min-inline-size: 150px;
  display: flex; align-items: center; gap: .6rem;
  padding-block: .65rem; padding-inline: .9rem;
  background: var(--card); font-size: .82rem; font-weight: 500; color: var(--text-faint);
}
.step .n {
  font-family: var(--font-mono); flex: none;
  color: var(--text-muted); font-weight: 600; font-size: .72rem;
  direction: ltr; unicode-bidi: isolate;
}
.step.done { color: var(--text-secondary); }
.step.done .n { color: var(--signal-ink); }
.step.active { background: var(--ink); color: var(--bg-elevated); font-weight: 600; }
.step.active .n { color: var(--primary-bright); }

.step-chip {
  display: inline-block; font-family: var(--font-mono); font-size: .66rem; font-weight: 600;
  letter-spacing: .08em; color: var(--text-muted);
  direction: ltr; unicode-bidi: isolate;
  margin-block-end: .5rem;
}

/* ---------- shift bar ----------
   One row: state, who and where, and the close action pushed to the far end.
   The status chip is a bordered object, so it cannot sit mid-sentence in a
   "·"-separated paragraph — it reads as a broken line. Keep it a bar. */
.shift-bar { display: flex; align-items: center; gap: .85rem; flex-wrap: wrap; }
.shift-bar .inline-form { display: flex; margin-inline-start: auto; }
.shift-meta { color: var(--text-secondary); font-size: .9rem; }
.shift-meta .sep { color: var(--text-faint); margin-inline: .4rem; }

/* ---------- landing hero — flat near-black, no gradients ---------- */
.hero-tech {
  background: var(--ink);
  color: var(--bg-elevated);
  border: 1px solid var(--ink);
  padding: clamp(2rem, 4.5vw, 3.6rem);
  margin-block-end: 1.2rem;
  position: relative;
  overflow: hidden;
}
.hero-tech::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.03) 1px, transparent 1px);
  background-size: 44px 44px;
}
.hero-inner { position: relative; max-inline-size: 720px; }
.hero-tech h1 {
  font-size: clamp(2rem, 4.4vw, 3.3rem); line-height: 1.08; margin-block-end: .9rem;
  font-weight: 700; letter-spacing: -0.035em; color: #fff;
}
.hero-tech p { color: rgba(255,255,255,.72); font-size: 1.05rem; max-inline-size: 620px; line-height: 1.65; }
.badges { display: flex; gap: .5rem; flex-wrap: wrap; margin-block: 1.2rem .2rem; }
.hero-badge {
  font-family: var(--font-mono); font-size: .7rem; font-weight: 500; color: var(--primary-bright);
  border: 1px solid var(--ink-4);
  padding-block: .25rem; padding-inline: .7rem;
  direction: ltr; unicode-bidi: isolate;
}
.hero-tech .cta { display: flex; gap: .7rem; margin-block-start: 1.6rem; flex-wrap: wrap; position: relative; }
.btn-glow { background: var(--primary); color: #fff; border-color: var(--primary); font-weight: 800; }
.btn-glow:hover { background: #fff; border-color: #fff; color: var(--ink); }
.btn-ghost { background: transparent; color: #fff; border: 1px solid var(--ink-4); }
.btn-ghost:hover { background: var(--ink-3); color: #fff; border-color: var(--ink-4); }
.hero-stats {
  position: relative; display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1px; background: var(--ink-3); border: 1px solid var(--ink-3); margin-block-start: 2.2rem;
}
.hstat { background: var(--ink-2); padding: 1rem 1.2rem; }
.hstat .num {
  font-family: var(--font-mono); font-size: 1.7rem; font-weight: 600; color: var(--primary-bright);
  direction: ltr; unicode-bidi: isolate; letter-spacing: -0.03em;
}
.hstat .lbl { font-size: .76rem; color: rgba(255,255,255,.6); margin-block-start: .15rem; }

/* ---------- service-first landing ---------- */
.hero-compact { padding-block-end: clamp(1.8rem, 3vw, 2.8rem); }
.hero-compact h1 { font-size: clamp(1.7rem, 3.2vw, 2.4rem); }
.verify-panel {
  position: relative;
  background: var(--ink-2);
  border: 1px solid var(--ink-3);
  padding: 1.3rem 1.4rem;
  margin-block-start: 1.5rem;
}
.verify-form {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto;
  gap: .9rem;
  align-items: end;
}
.verify-form label { color: rgba(255,255,255,.72); }
.verify-form input { background: #fff; border-color: transparent; }
.vf-or {
  color: rgba(255,255,255,.45); font-size: .82rem; font-weight: 600;
  padding-block-end: .8rem;
}
.vf-btn { min-block-size: 2.9rem; padding-inline: 1.8rem; }
@media (max-width: 760px) {
  .verify-form { grid-template-columns: 1fr; }
  .vf-or { padding-block-end: 0; text-align: center; }
}
.how-list { padding-inline-start: 1.15rem; margin: 0; }
.how-list li { font-size: .89rem; color: var(--text-secondary); margin-block-end: .45rem; }
.how-list li::marker { font-family: var(--font-mono); color: var(--signal-ink); font-weight: 600; }
.strip-stats {
  display: flex; gap: .8rem; justify-content: center; flex-wrap: wrap;
  color: var(--text-muted); font-size: .84rem; margin-block-start: 1.5rem;
}
.strip-stats strong { color: var(--text-secondary); }
.strip-stats .dot { color: var(--text-faint); }

/* ---------- how it works ---------- */
.how-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 1px; background: var(--border); border: 1px solid var(--border); }
.how-card {
  padding: 1.3rem;
  background: var(--card);
  transition: background var(--dur) var(--ease-out);
}
.how-card:hover { background: var(--bg-elevated); }
.how-card p { margin-block-start: .6rem; font-size: .88rem; color: var(--text-secondary); line-height: 1.6; }
.how-n {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-weight: 600; font-size: .78rem;
  color: var(--signal-ink); letter-spacing: .08em;
  direction: ltr; unicode-bidi: isolate;
}

/* ---------- admin nav ---------- */
.admin-nav {
  display: flex; gap: 1.4rem; flex-wrap: wrap;
  border-block-end: 1px solid var(--border);
  margin-block-end: 1.5rem;
}
.admin-nav a, .admin-nav strong {
  padding-block: .55rem;
  font-size: .89rem; font-weight: 500;
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
}
.admin-nav a { color: var(--text-muted); }
.admin-nav a:hover { color: var(--text); text-decoration: none; }
.admin-nav strong { color: var(--text); border-color: var(--ink); font-weight: 600; }

/* ---------- report head + print ---------- */
.report-head {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 1rem; flex-wrap: wrap; margin-block-end: 1rem;
}
@media print {
  .statusbar, .topbar, .footer, .screen-only, .admin-nav, .bot-fab, .bot-panel { display: none !important; }
  body { background: #fff; }
  .page { inline-size: 100%; padding-block: 0; }
  .card { break-inside: avoid; }
  a { color: inherit; text-decoration: none; }
}

/* ---------- support bot widget ---------- */
.bot-fab {
  /* ⚠ THE OTHER CORNER FROM THE ACCESSIBILITY BUTTON, not stacked above it.
     Both started at inset-block-end 22px / inset-inline-start 22px — the same
     corner, exactly overlapping, so the assistant covered the accessibility
     control, which is the worst possible pair to get wrong. Stacking it 5.9rem
     up cleared the overlap and still put two floating controls in one corner;
     Rami asked for it on the other side, so it is on the other side. .a11y-fab
     holds inset-inline-start; this holds inset-inline-end, and neither can
     reach the other however either one grows.

     ⚠ AND IT SAYS WHAT IT IS. A bare dark square with an icon told a sighted
     visitor nothing about what it opened. Drawn both ways in the design and
     Rami picked the labelled one. */
  position: fixed; inset-block-end: 1.4rem; inset-inline-end: 1.4rem; z-index: 90;
  min-block-size: 56px; padding-inline: 22px 18px; border-radius: 28px;
  background: var(--p-ink, var(--ink)); color: var(--p-paper, #fff); border: 0;
  box-shadow: 0 8px 20px rgb(11 18 17 / .28); cursor: pointer;
  display: flex; align-items: center; gap: .6rem;
  font: inherit; font-size: 15px; font-weight: 600;
  transition: background var(--dur-fast) var(--ease-out);
}
.bot-fab svg { color: var(--p-brand-bright, var(--primary-bright)); flex: none; }
.bot-fab:hover { background: var(--p-ink-2, var(--ink-3)); }
@media (max-width: 560px) {
  /* the label costs too much width beside a phone's own edge gestures */
  .bot-fab { padding-inline: 16px; }
  .bot-fab-t { display: none; }
}
.bot-panel {
  /* opens from the button, so it shares its corner */
  position: fixed; inset-block-end: 5.6rem; inset-inline-end: 1.4rem; z-index: 90;
  inline-size: min(372px, calc(100vw - 2rem)); block-size: min(520px, 72vh);
  background: var(--p-paper, var(--card));
  border: 1px solid var(--p-line, var(--ink));
  box-shadow: 0 24px 48px rgb(11 18 17 / .16);
  display: flex; flex-direction: column; overflow: hidden;
}
.bot-head {
  display: flex; justify-content: space-between; align-items: flex-start; gap: .75rem;
  padding: 1rem 1.1rem; background: var(--p-ink, var(--ink)); color: var(--p-paper, #fff);
}
.bot-title { font-weight: 600; font-size: 16px; letter-spacing: -.02em; }
.bot-sub { font-size: 12.5px; line-height: 1.5;
  color: var(--p-onink, rgb(255 255 255 / .6)); }
/* a 32px target with a real glyph in it — see the note in bot.js */
.bot-close { flex: none; inline-size: 32px; block-size: 32px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--p-line-dark, rgb(255 255 255 / .28));
  color: var(--p-faint, rgb(255 255 255 / .7)); cursor: pointer; }
.bot-close:hover { color: #fff; border-color: currentColor; }
.bot-msgs { flex: 1; overflow-y: auto; padding: 1rem; display: flex;
  flex-direction: column; gap: .65rem; }
.bot-msg {
  max-inline-size: 88%; padding: .7rem .9rem;
  font-size: 14px; line-height: 1.7; white-space: pre-wrap; text-wrap: pretty;
}
.bot-msg-user { align-self: flex-end; background: var(--p-ink, var(--ink));
  color: var(--p-paper, var(--bg-elevated)); }
.bot-msg-model { align-self: flex-start; background: var(--p-paper, var(--bg-elevated));
  color: var(--p-ink, var(--text)); border: 1px solid var(--p-line, var(--border)); }
/* the ochre rule marks where the assistant starts speaking */
.bot-msg-model:first-child { border-block-start: 2px solid var(--p-brand-bright, var(--primary-bright)); }
/* ⚠ A 44px ROW. The composer was a .6rem-padded strip with a squeezed send
   button beside it — under the 44px minimum a touch target needs, and the
   button was narrower than its own word. */
.bot-form { display: flex; gap: .5rem; padding: .75rem;
  background: var(--p-wash, var(--bg-elevated));
  border-block-start: 1px solid var(--p-line, var(--border)); }
.bot-form .bot-input {
  flex: 1; min-inline-size: 0; min-block-size: 44px; padding-inline: .8rem;
  font: inherit; font-size: 14px; border-radius: 0;
  color: var(--p-ink, var(--text)); background: var(--p-paper, #fff);
  border: 1px solid var(--p-line-2, var(--border)); }
.bot-send { flex: none; min-block-size: 44px; padding-inline: 1.15rem;
  font: inherit; font-size: 14px; font-weight: 700; cursor: pointer;
  color: var(--p-ink, #fff); background: var(--p-brand-bright, var(--primary));
  border: 1px solid var(--p-brand-bright, var(--primary)); border-radius: 0; }
.bot-send:hover { filter: brightness(.94); }
/* ⚠ THE FOCUS RING SITS ON THE FIELD, NOT OUTSIDE IT. The sitewide ring is
   `2px solid --p-brand-text` at `outline-offset: 2px`, which is right for a
   link or a button standing in open space — around a bordered input inside a
   12px-padded strip it draws a SECOND frame two pixels out from the first, and
   the composer arrived looking like a field inside a box inside a box. Rami put
   the two states side by side and picked the clean one.
   ⚠ AND THERE WERE THREE FRAMES, NOT TWO. Written first as
   `.bot-form :focus-visible { outline-offset: -1px }`, which changed nothing:
   `.pub input:focus-visible` is (0,2,1) and that selector is (0,2,0), so the
   2px offset simply won. Underneath both, the app-wide `input:focus` adds
   `box-shadow: inset 0 0 0 1px var(--primary-edge)` — the certificates app's
   navy — which is the thin inner line in Rami's screenshot. Field border,
   inset navy ring, offset ochre ring: three edges around one input.

   One frame now, sitting 2px inside the field so it covers the border rather
   than racing it, with the inset shadow cleared and the border taking the ring's
   own colour. Still 2px of #5c4517 at 9.06:1 on white — far past the 3:1 a focus
   indicator owes — so nothing about its visibility is traded for the tidier
   shape. Specific enough (0,3,1) to beat both rules it has to beat, which is
   the whole reason the first attempt did nothing. */
.pub .bot-form input:focus, .pub .bot-form input:focus-visible,
.pub .bot-form button:focus-visible {
  outline: 2px solid var(--p-brand-text); outline-offset: -2px;
  border-color: var(--p-brand-text); box-shadow: none;
}
/* ⚠ TWO STALE RULES DELETED FROM HERE, and they would have silently won.
   `.bot-form .bot-input { min-block-size: 2.5rem }` and `.bot-send { flex: none }`
   sat immediately BELOW the block above at equal specificity, so the composer
   would have kept its 40px height however carefully the rule above set 44px —
   the same later-wins trap that made the mobile nav fix change nothing earlier
   in this project. Both are folded into the block above; nothing is lost. */

/* ---------- POC badge ----------
   Lives on the dark status strip now, so it is drawn light-on-dark. It used
   to force `direction: ltr` for the bare word "POC"; the label is a Hebrew
   sentence, and forcing LTR on it put the parenthesis on the wrong end. */
.poc-badge {
  font-size: 10px; font-weight: 700; letter-spacing: .02em; line-height: 1.4;
  color: #fff; background: var(--primary);
  padding-block: 1px; padding-inline: .5rem; flex: none;
}

/* ---------- paint estimator ---------- */
/* THE SIX SECTIONS. Each is a <details> that is also a .card, so a closed one
   is a single line carrying its own state and the page is six lines instead of
   six screens. `.card` supplies the frame; only the summary row is new. */
.card.formstep > summary {
  cursor: pointer; display: flex; align-items: baseline; gap: .8rem;
  flex-wrap: wrap; list-style: none;
}
/* A flex summary loses its native marker box, so the disclosure triangle is
   drawn here. A CARET: along the reading direction when the section is closed,
   down when it is open.

   THE ROTATION IS PER DIRECTION, and the first version of this was wrong in the
   only direction this product ships in. The borders are logical, so under
   `dir="rtl"` they resolve to LEFT+bottom instead of RIGHT+bottom and the
   shape's own tip already points at 225° rather than 135°. A single fixed angle
   on a base shape that mirrors itself does not mirror with it: measured in
   Chrome, RTL closed pointed DOWN (the LTR open state) and RTL open pointed
   LEFT. Rotating a mirrored shape by the mirrored angle is what actually works,
   so each direction gets its own pair. */
.card.formstep > summary::-webkit-details-marker { display: none; }
.card.formstep > summary::before {
  content: ""; flex: none; align-self: center;
  inline-size: .5rem; block-size: .5rem;
  border-inline-end: 2px solid var(--text-muted);
  border-block-end: 2px solid var(--text-muted);
  transform: rotate(-45deg); transition: transform var(--dur) var(--ease-out);
}
.card.formstep[open] > summary::before { transform: rotate(45deg); }
[dir="rtl"] .card.formstep > summary::before { transform: rotate(45deg); }
[dir="rtl"] .card.formstep[open] > summary::before { transform: rotate(-45deg); }
.card.formstep > summary > h2 { display: inline; margin: 0; }
.card.formstep[open] > summary { margin-block-end: 1rem; }
/* The state line carries values the summary has no other way to show — a plate
   number, a rate with its ₪, an hours range — dropped into a Hebrew sentence.
   Every one of those is a Latin/digit run inside RTL text, which is the shape
   that reorders an allocation number, so the line isolates them. `isolate` on
   the container, because the values arrive as bare interpolations rather than
   as elements that could each carry their own. */
.card.formstep > summary > .formstep-state {
  color: var(--text-muted); font-size: .85rem; margin-inline-start: auto; text-align: start;
  unicode-bidi: isolate;
}
/* The marker is a Latin triangle in an RTL document; leave it to the browser's
   own direction handling rather than positioning it by hand. */
.card.formstep > summary::marker { color: var(--text-faint); }
.card.formstep > summary:focus-visible { outline: 2px solid var(--p-brand-text); outline-offset: 2px; }

/* THE ANSWER. The total, once, at the size of the question — everything else in
   the result card is the working behind it. */
.card-result .headline {
  display: flex; align-items: baseline; gap: .6rem 1.2rem; flex-wrap: wrap;
  padding-block: .4rem 1.1rem; margin-block-end: 1.1rem;
  border-block-end: 1px solid var(--border-hairline);
}
.card-result .headline-label { color: var(--text-muted); font-size: .9rem; }
.card-result .headline-num {
  font-size: clamp(26px, 4vw, 40px); font-weight: 700; line-height: 1.15;
  direction: ltr; unicode-bidi: isolate; font-variant-numeric: tabular-nums;
}
.card-result .headline-sub {
  color: var(--text-muted); font-size: .85rem; unicode-bidi: isolate;
}
.card-result .headline > .btn { margin-inline-start: auto; }

/* THE BAR THAT FOLLOWS THE PAGE. «חשב» was the last control of the last
   section; with the sections collapsed it would have needed one opened first.
   Sticky, so the action and the last figure stay in reach while the form above
   is being changed. In normal flow, so with no CSS it is simply the last row.
   The bottom safe-area inset is added to its own padding rather than left to
   the page, or the bar sits under a phone's home indicator. */
.actionbar {
  position: sticky; inset-block-end: 0; z-index: 5;
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--border);
  padding: .9rem 1.2rem;
  padding-block-end: calc(.9rem + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -2px 10px rgb(8 38 70 / .07);
}
.actionbar-total { display: flex; align-items: baseline; gap: .5rem; }
.actionbar-total strong {
  font-size: 1.15rem; direction: ltr; unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
}
.actionbar > .btn:first-of-type { margin-inline-start: auto; }
/* The bar floats over the end of the page, so a control scrolled to by the
   keyboard can land underneath it: the focus ring is drawn and the thing it
   rings is covered. The scroll container keeps the bar's own height clear. */
html:has(.actionbar) { scroll-padding-block-end: 6rem; }
@media print { .actionbar { position: static; box-shadow: none; } }
.paint-tbl select { inline-size: 100%; min-inline-size: 0; font-size: .85rem; padding-block: .3rem; }
.paint-tbl td, .paint-tbl th { vertical-align: middle; }
/* One options column now, holding a disclosure instead of four columns of
   always-on controls. 12rem fits the collapsed summary and the two selects once
   opened; the panel-name column stays the only greedy one, so the browser
   honours the hint. The old pair of 12rem select columns plus a 14rem options
   column was most of the ~75rem that made this table scroll sideways on a
   phone, with the hours — the answer — off the far edge. */
.paint-tbl col.c-opts { inline-size: 12rem; }
/* Stack the disclosure's contents: two labelled selects, then the checkboxes.
   `vertical-align: middle` above centres a closed row; once open the cell is
   tall and the controls should start at the top with the panel name. */
.paint-tbl .row-opts > summary { cursor: pointer; padding-block: .2rem; }
.paint-tbl .row-opts > label { display: block; margin-block-start: .45rem; }
.paint-tbl .row-opts > label.stacked > span { display: block; margin-block-end: .15rem; }
.paint-tbl tr:has(.row-opts[open]) > * { vertical-align: top; }
/* `4.42–4.93` must not wrap mid-range — a broken range reads as two numbers. */
.paint-tbl col.c-hours { inline-size: 6.5rem; }
.paint-tbl td.num-cell { white-space: nowrap; }
/* Row headers are panel NAMES, not column labels — `.tbl th` is tuned for the
   latter (mono, tracked out, 0.68rem) and renders Hebrew words as loose
   letters. Reset it for the row-header scope only. */
.paint-tbl tbody th, .tbl tbody th[scope="row"] {
  font-family: inherit; font-size: .89rem; letter-spacing: normal;
  color: var(--text); border-block-end: 1px solid var(--border-hairline);
}
.paint-tbl tbody th label { cursor: pointer; }
/* The selected rows are also the only rows with an hours figure, so the tint is
   a second cue rather than the sole one — colour never carries this alone. */
.paint-tbl .row-on { background: var(--primary-tint); }
/* A wrapping flex row put these on ragged starts — three options of unequal
   label length wrapped 2 + 1, and the second item on the first line began
   nowhere near the item below it. A single column gives every checkbox the
   same start edge, which is what makes a list of options scannable. */
.paint-tbl .opts { display: grid; justify-items: start; gap: .15rem; }

.chk { display: inline-flex; align-items: center; gap: .35rem; font-size: .83rem; cursor: pointer; }
.chk input { inline-size: 1rem; block-size: 1rem; flex: none; }

/* ₪ (U+20AA) is missing from the mono stack and renders as tofu, so the
   currency mark stays in the sans face while the figures stay monospaced.
   It must LEAD the number rather than trail it: as a trailing span its x moved
   with the width of each range (measured 413px on "319–602" vs 446px on
   "1,839–2,322"), so no two money rows lined up. Leading, inside the cell's own
   LTR isolate, every ₪ lands on the same x — and that is the order store.html
   already uses for prices. */
.cur { font-family: var(--font-sans); margin-inline-end: .15em; }

/* ---------- שעתון צבע — result table ----------
   Nine unrelated rows in one flat list made the total the hardest number to
   find; the rows are grouped time / money / quantities. */
.result-tbl .rg-head th {
  padding-block: .85rem .35rem;
  color: var(--text-faint); border-block-end: 0;
  font-size: .62rem; letter-spacing: .14em;
}
.result-tbl tbody + tbody .rg-head th { border-block-start: 1px solid var(--border); }
.result-tbl tbody tr:last-child td,
.result-tbl tbody tr:last-child th { border-block-end: 1px solid var(--border-hairline); }
/* a row header may now carry a one-line basis under its label */
.result-tbl tbody th[scope="row"] small {
  display: block; margin-block-start: .2rem;
  font-family: var(--font-sans); font-size: .72rem; letter-spacing: 0;
  color: var(--text-faint); font-weight: 400;
}
.result-tbl .lead { font-size: 1.05rem; font-weight: 600; }
.result-tbl .money { font-size: .95rem; }
/* The total closes the money group. It used to carry a `big` class that no rule
   anywhere matched (`.verdict .big` is scoped to the verdict box), so the
   emphasis it was written to have never actually rendered. */
.result-tbl tr.sum th, .result-tbl tr.sum td { border-block-start: 1px solid var(--ink); }
.result-tbl tr.sum th[scope="row"] { color: var(--text); }
.result-tbl tr.sum .money { font-size: 1.35rem; font-weight: 700; letter-spacing: -0.02em; }

.judgment-row th, .judgment-row td { background: var(--primary-tint); }

/* The description takes the room; the hours box needs only a few characters,
   and a full-width number field beside it reads as a second text column. */
.judgment-tbl col.c-hours { inline-size: 9rem; }

/* The instance table carries eight columns; let it scroll inside .tbl-wrap
   rather than squeezing the selects into unreadable widths. */
.paint-tbl { min-inline-size: 62rem; }
.paint-tbl input[type="radio"] { inline-size: 1.05rem; block-size: 1.05rem; }

.note-row td { padding-block: .3rem; background: var(--bg-elevated); }
.note-row:hover td { background: var(--bg-elevated); }

@media (max-width: 640px) {
  /* 2rem is 16% of a 390px phone. Give the content back the room. */
  :root { --gutter: .9rem; }
  .page { padding-block: 1.2rem 2rem; }
  .nav { gap: 2px; }
  h1 { font-size: 1.6rem; }
  .paint-tbl .opts { gap: .2rem; }
}

/* ---------- accessibility utilities ---------- */
.visually-hidden {
  position: absolute; inline-size: 1px; block-size: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ============================================================================
   PUBLIC SITE — איגוד המוסכים בישראל
   Design: THE COLLEGE'S OWN, carcollege.co.il, measured 15.9.2026.

   ⚠ THIS REPLACED THE "IGA Website" EXPORT, AND THE SWAP WAS ASKED FOR.
   The association's site and the college's were two designs, and the college's
   is the one that is live, unchanged, and that a member already recognises —
   iga.org.il's own footer links it. Rami, 15.9.2026: «restore the original
   college design and actually use it in the IGA main site». So the tokens here
   are no longer a house style: they are read off the running site, the same way
   the export used to be read off a file.

   MEASURED, NOT REMEMBERED. Every value below came out of getComputedStyle on
   carcollege.co.il on 15.9.2026, not out of a screenshot or a memory of one:
     ink / buttons / body text   rgb(8,38,70)     #082646
     the one tinted surface      rgb(239,244,246) #eff4f6
     the signal on the dark      rgb(255,167,59)  #ffa73b
     the accent rule under cards rgb(0,130,244)   #0082f4
     card radius 20px · button radius 7px · h1 60/54 w700 centred
   Re-measure before changing one; the live site is the source of truth and it
   is still there.

   ⚠ TWO OF ITS COLOURS ARE NOT TEXT-SAFE AND ARE NOT USED AS TEXT ON LIGHT.
   Measured on the worst surface each lands on:
     #ffa73b  1.94:1 on paper  → NEVER text on light. 7.88:1 on the ink, which
                                 is exactly what --p-brand-bright means here.
     #0082f4  3.82:1 on paper  → clears the 3:1 WCAG 1.4.11 asks of a non-text
                                 component and misses the 4.5:1 it asks of
                                 text, so it is the 5px rule under a card and
                                 nothing else. --p-blue stays a darker blue for
                                 anything that carries words.
   Same split the מייסטר and the old green blocks document: a designer picks the
   colour, the ratio decides where it may be used. tests/test_a11y.py recomputes
   all of it and fails on a regression.

   Scoped to `.pub` on <body>. The certificates app keeps its own palette
   untouched: the two are different products sharing one stylesheet, and a
   global token swap would have repainted every certificate screen.

   ⚠ THE SQUARE IS GONE, AND THAT IS THE CHANGE, NOT A REGRESSION. The note that
   stood here said "SQUARE — the export contains no border-radius anywhere" and
   :root still says the same of the certificates app, where it is still true.
   The college rounds: 20px on a card, 7px on a button. A refactor that sets
   these back to 0 has undone the design, not tidied it.
   TIGHT stays: display type runs -0.02em to -0.04em tracking.
   ============================================================================ */
.pub {
  --p-ink: #082646;         /* the college's navy — ink, fills and buttons alike */
  --p-ink-2: #0b3059;       /* the dark band, one step off the ink */
  --p-ink-3: #24456b;       /* secondary text — 9.82:1 on paper */
  --p-muted: #4d6a85;       /* card copy, counts, table headers — 5.65 / 5.10 */
  --p-faint: #9fb4c6;       /* on the dark bands only — 7.14:1 on the ink */
  --p-wash: #eff4f6;        /* the one tinted surface, and the footer's ground */
  --p-line: #dde5ea;
  /* ⚠ DEFINED HERE SO A BRAND CAN OVERRIDE THEM. These four arrived with a
     brand palette and were at first set ONLY in a brand block, which
     tests/test_brands.py refuses for a good reason: a custom property nothing
     defines has no value to fall back to, so every OTHER brand renders the
     var()'s fallback — or nothing — and it looks like a colour that was
     chosen. */
  --p-muted-2: #4d6a85;     /* second-rank text on light; == --p-muted here */
  --p-onink: #9fb4c6;       /* labels on the dark bands; == --p-faint here */
  --p-line-2: #c6d3dc;      /* a heavier hairline */
  --p-line-dark: #24456b;   /* ⚠ the hairline ON THE DARK BANDS, and its own
                               token on purpose. It was first written as
                               --p-ink-3, which in this system means SECONDARY
                               TEXT — a brand that maps that to a mid-grey turns
                               the figure row's separators into bars across the
                               band instead of hairlines. Two different jobs
                               that happen to share a value here and stop
                               sharing one on somebody else's palette. */
  --p-ground: #ffffff;      /* the page's ground; the sections carry the tint */
  --p-brand: #082646;
  --p-brand-text: #082646;  /* 15.26:1 on paper — one value carries edges,
                               fills and text, so there is no pair to keep in
                               step. The green this design replaced needed two. */
  --p-brand-bright: #ffa73b;   /* on dark surfaces ONLY — see the note above */
  --p-rule: #0082f4;           /* the 5px rule under a card. NEVER text. */
  --p-red: #a82820;         /* recalls only — 7.02:1 with white */
  --p-blue: #2f5dbf;
  --p-paper: #ffffff;
  --p-mono: "JetBrains Mono", ui-monospace, Menlo, monospace;
  /* Geometry. The certificates app stays square on the app's own tokens; the
     public site rounds, because the college does. Two values, and they are not
     interchangeable: a button at 20px reads as a pill.
     ⚠ The word for the app's token block may not appear in this comment —
     test_the_two_products_are_one_product asserts the string is absent from
     the whole .pub block, to catch a stray redefinition, and a comment
     mentioning it fails the same way a real one would. */
  --p-radius: 20px;
  --p-radius-btn: 7px;
  background: var(--p-paper); color: var(--p-ink);
}
.pub main { display: block; max-inline-size: none; padding: 0; margin: 0; }

/* ---- status bar: the association is awake ---- */
.pub-status {
  display: flex; align-items: center; gap: 1.5rem;
  padding: .55rem 2rem; background: var(--p-ink); color: var(--p-faint);
  font-size: 11px; letter-spacing: .04em;
}
.pub-status .live { display: inline-flex; align-items: center; gap: .45rem; color: var(--p-brand-bright); }
.pub-status .dot {
  inline-size: 6px; block-size: 6px; border-radius: 50%; background: currentColor;
  animation: igapulse 2.4s ease-in-out infinite;
}
.pub-status .since { margin-inline-start: auto; }
.pub-status .clock { font-family: var(--p-mono); color: var(--p-wash); }
@media (prefers-reduced-motion: reduce) { .pub-status .dot { animation: none; } }

/* ---- masthead ---- */
.pub-head {
  display: flex; align-items: center; gap: 2rem;
  padding: 1rem 2rem; border-block-end: 1px solid var(--p-line); background: var(--p-paper);
}
.pub-brand { display: flex; align-items: center; gap: .8rem; }
.pub-mark {
  inline-size: 38px; block-size: 38px; flex: none;
  background: var(--p-brand); color: var(--p-paper);
  display: grid; place-items: center; font-size: 26px; font-weight: 300; line-height: 1;
}
/* Scoped to the wordmark, NOT to every span in the brand: `.pub-brand span`
   also matched .pub-mark and beat it on specificity, which repainted the logo
   glyph 9.5px grey-on-green and made it invisible. */
.pub-wordmark b { display: block; font-size: 15px; font-weight: 800; letter-spacing: -.02em; }
.pub-wordmark small {
  display: block; font-family: var(--p-mono); font-size: 9.5px;
  letter-spacing: .18em; color: var(--p-muted);
}
.pub-nav { display: flex; gap: 1.6rem; margin-inline: auto; }
.pub-nav a { color: var(--p-ink-3); font-size: 15px; font-weight: 500; letter-spacing: 0; }
.pub-nav a:hover, .pub-nav a.on { color: var(--p-brand-text); text-decoration: none; }

/* Submenus for Arie's six groups. CSS only — pub_layout.html says why there is
   no JS and no role="menu". :focus-within is what makes it keyboard-operable:
   tabbing into the group link opens the panel and tabbing past the last child
   closes it, with no state to get out of sync. Visibility rather than display,
   so the links keep their place in the tab order. */
.pub-navgroup { position: relative; }
/* ⚠ IT HANGS FROM ITS OWN ITEM, IT IS NOT CENTRED UNDER IT. This was
   `inset-inline-start: 50%` with `transform: translateX(50%)` — a centred
   panel, which is fine while a panel is about as wide as its trigger and
   wrong the moment it is not. On the college's אודות the panel is 430px of
   long Hebrew items under a 70px word: centred, it reached almost to
   "פרויקטים ושת״פ" two items away and read as belonging to that one instead.
   Reported 8.9.2026 with a screenshot.
   Aligning the panel's inline-start to the group's inline-start puts their
   RIGHT edges together in Hebrew and their LEFT edges together in a
   translation, which is what a reader expects of a menu in either direction —
   and it needs no transform, so nothing physical is left in a logical rule.
   (translateX is physical and was correct only by accident here: it centres in
   RTL and would have thrown the panel a full width sideways in LTR.) */
.pub-submenu {
  position: absolute; inset-block-start: calc(100% + .55rem); inset-inline-start: 0;
  min-inline-size: 215px; z-index: 40;
  background: var(--p-paper); border: 1px solid var(--p-line);
  box-shadow: 0 12px 32px rgb(11 18 17 / .13);
  opacity: 0; visibility: hidden; transition: opacity .12s ease;
}
/* The .55rem the panel is offset by is DEAD SPACE, and it broke the menu: on
   the way down to an item the pointer left .pub-navgroup, :hover went false and
   the panel vanished before it could be reached — open, visible and unusable.
   Bridge it with a transparent strip belonging to the panel, so the group stays
   hovered the whole way across. It inherits the panel's visibility, so no
   invisible hover trap sits over the page while the menu is shut. A hover-intent
   delay was the alternative and it is worse: a timer that holds a menu open
   after the pointer has left is its own bug. */
.pub-submenu::before {
  content: ""; position: absolute; inset-inline: 0;
  inset-block-end: 100%; block-size: .55rem;
}
.pub-navgroup:hover .pub-submenu,
.pub-navgroup:focus-within .pub-submenu { opacity: 1; visibility: visible; }
/* A menu entry with no page of its own — the academies have nine of them
   (אודות, תקנונים, שער לימודים…). It sits in the same row as its sibling links
   and must not read as a different KIND of thing, so it matches them exactly
   and differs only in not being clickable. Without this rule it inherited the
   body font: 15px/400 next to 13.5px/600, visibly larger than its neighbours. */
/* The group label is a nav item that happens not to be a link, so it tracks
   .pub-nav a exactly — sized separately, they read as two different menus. */
.pub-navparent { font-size: 15px; font-weight: 500; color: var(--p-ink-3); cursor: default; }
.pub-submenu ul { list-style: none; margin: 0; padding: .4rem 0; }
/* Third-level items, indented under their parent. */
.pub-submenu ul ul { padding: 0 0 .3rem; }
.pub-submenu ul ul a, .pub-submenu ul ul .pub-navparent {
  padding-inline-start: 1.7rem; font-size: 12.5px; font-weight: 400;
}
.pub-submenu a {
  display: block; padding: .5rem .95rem; font-size: 13px; font-weight: 500;
  color: var(--p-ink); min-block-size: 24px;
}
/* ⚠ AND THE GROUP LABEL GETS THE SAME BOX AS A LINK. .pub-navparent carries
   only font and colour — the padding lives on `.pub-submenu a`, and a label is
   not an anchor — so inside a panel it had NO padding at all: measured on the
   college's אודות, "תקנונים" put its text at x=726 while every link beside it
   sat at 711, and stood 16px tall against their 37px. One item jutting out of
   a column of eight and squashed against its neighbours, which is what
   "this is not nice" was pointing at.
   Scoped to .pub-submenu on purpose: in the NAV ROW the same class must keep
   matching its sibling links exactly, which is what the note above it is for. */

/* `display: block` for the same reason as the padding: .pub-navparent is
   inline in the nav row, where it belongs to a flex line, and an inline box
   does not take the padding's full height — the label measured 32px against
   its links' 37px even once it was padded. Scoped, so the row is untouched. */
.pub-submenu .pub-navparent { display: block; padding: .5rem .95rem;
  min-block-size: 24px; }
.pub-submenu a:hover, .pub-submenu a[aria-current] {
  background: var(--p-wash); color: var(--p-brand-text); text-decoration: none;
}
@media (prefers-reduced-motion: reduce) { .pub-submenu { transition: none; } }

/* ---- the content pages behind that nav ---- */
.pub-prose { max-inline-size: 74ch; margin-block-start: 1.4rem; }
/* ⚠ THE LEVELS HAVE TO BE TELLABLE APART AT A GLANCE, and they were not.
   h2 was 19px/800 and h3 16.5px/800 — 2.5px at the same weight, which in Hebrew
   (no ascender/descender rhythm to help) reads as one size. On שירותים the h2
   that opens the whole second half of חברות באיגוד, "אתה חבר מגיע לך יותר",
   was indistinguishable from the h3 beneath it. Reported 7.9.2026.
   Three things separate them now, so no single one has to carry it:
   size (21 / 16.5), and a rule above the h2, and the space before it. */
.pub-prose h2 { font-size: 24px; font-weight: 700; margin-block: 2.6rem .7rem;
  padding-block-start: 1.1rem; border-block-start: 1px solid var(--p-line);
  letter-spacing: -.015em; }
/* The first heading of a body opens the page — it needs no rule above it and no
   gap, because the lead is already there.
   ⚠ EVERY LEVEL, not only h2. The compression above maps the SHALLOWEST tag a
   body uses onto h2, which is not necessarily the tag of the body's FIRST
   block: a body opening with a subordinate heading before its parent renders
   h3 first and would keep its own margin. No live instance was found, and the
   assumption costs nothing to remove. */
.pub-prose > :is(h2, h3, h4, h5, h6):first-child {
  margin-block-start: 0; padding-block-start: 0; border-block-start: 0; }
.pub-prose h3 { font-size: 19px; font-weight: 700; margin-block: 1.6rem .45rem;
  letter-spacing: -.01em; color: var(--p-ink); }
/* The compression rule can emit an h4 once a body uses three distinct levels.
   None does today; a heading with no rule at all would inherit the browser
   default and look like a mistake, which is worse than an unused three lines. */
.pub-prose h4 { font-size: 15px; font-weight: 700; margin-block: 1.1rem .35rem;
  color: var(--p-ink-2, var(--p-ink)); }
/* 16px, up from 14.5. The college runs 17px body; Heebo sets a shade larger
   than Roboto at the same nominal size, so 16 lands where 17 does there. */
.pub-prose p { font-size: 16px; line-height: 1.9; color: var(--p-ink-2, var(--p-ink)); margin-block-end: 1rem; }
/* ⚠ A REAL LIST. `.pub-prose-item` was a paragraph pretending to be one — see
   the note in _pub_prose.html. Logical properties throughout, so the marker
   sits on the right in Hebrew and would sit on the left in a translation
   without a second rule: `padding-inline-start` and the default marker
   position both follow the writing direction.
   The marker is quieter than the item text (--p-muted) so a long list scans as
   a shape rather than a wall; a NUMBER carries meaning, so it takes the
   association's own navy and a heavier weight. */
.pub-prose .pub-list { margin-block: .5rem 1.1rem; padding-inline-start: 1.35rem; }
.pub-prose .pub-list li { font-size: 16px; line-height: 1.9;
  color: var(--p-ink-2, var(--p-ink)); margin-block-end: .45rem;
  padding-inline-start: .25rem; }
.pub-prose .pub-list li::marker { color: var(--p-muted); }
.pub-prose .pub-list-num { list-style: decimal; }
.pub-prose .pub-list-num li::marker { color: var(--p-brand); font-weight: 700; font-size: 13px; }
/* A nested list, if a body ever carries one, must not restart the indent from
   the page edge. */
.pub-prose .pub-list .pub-list { margin-block: .35rem .35rem; }
/* A prose list item must not split across a printed page — that rule lives
   with every other page-break rule, in the one @media print block below. */
/* Historical photographs and press clippings on אבני דרך. They are small
   originals (331–608px wide) — max-inline-size:100% lets them shrink on a
   phone, and width:auto stops the intrinsic width attribute stretching them
   past their real resolution on a wide screen, where they would go soft. */
.pub-fig { margin: 1.4rem 0; }
/* ⚠ AND NO TALLER THAN ONE GLANCE. max-inline-size alone let a portrait photo
   fill the column and then the screen — the college's חזון page rendered a
   668x1000 original at 660x987, taller than the viewport it was read in, and 53
   of the 115 prose images across the three sites are over 480px tall. Height is
   the axis that was never capped, because when this rule was written the only
   figures were IGA's small landscape clippings.
   width:auto + max-block-size keeps the aspect ratio: the browser scales a
   replaced element on both axes. The figure is a LINK to the full file, so a
   scanned form or the Meister diploma is one click from being readable — see
   the note in templates/_pub_prose.html for why the cap and the link are one
   decision rather than two.
   MEASURED IN CHROME 7.9.2026 on /חזון-המכללה, because a stylesheet assertion
   cannot see a squashed picture: the 844x1264 file renders 321x480. 844/1264
   and 321/480 agree to three places, so the ratio survives the cap. */
.pub-fig img { max-inline-size: 100%; inline-size: auto; block-size: auto;
  max-block-size: 30rem;
  border: 1px solid var(--p-line); border-radius: 3px; background: #fff; }
.pub-fig-full { display: inline-block; line-height: 0; border: 0; }
/* A MARK — the association's own logos. No frame, no white plate, no radius:
   the הפלוס הירוק badge is a green disc on white and a border drew a box
   around it. Sized by its own weight in the page (11rem) rather than by the
   30rem cap that exists to stop a scanned form owning the screen, and it stays
   a link to the full file for anyone who wants it bigger. */
.pub-fig-mark { margin: 1.1rem 0; }
.pub-fig-mark img { max-block-size: 11rem; border: 0; border-radius: 0;
  background: none; }
.pub-fig-full:hover img, .pub-fig-full:focus-visible img { border-color: var(--p-brand-text); }
.pub-docs { list-style: none; margin: 1.6rem 0 0; padding: 0; max-inline-size: 74ch; }
.pub-docs li { border-block-end: 1px solid var(--p-line); padding-block: .8rem; }
.pub-docs a { font-size: 14.5px; font-weight: 600; }
.pub-docs-note { display: block; font-size: 12px; color: var(--p-muted); font-style: normal; margin-block-start: .25rem; }
/* The same call to action above the prose. It carries no top margin of its
   own — the lead is directly above it. */
.pub-external-top { margin-block: .2rem 1.6rem; }
.pub-external { display: flex; align-items: center; gap: .9rem; margin-block-start: 1.6rem; flex-wrap: wrap; }
.pub-external .num { font-family: var(--p-mono); font-size: 12px; color: var(--p-muted); }
.pub-cell-link { display: block; }
.pub-cell-link:hover { border-color: var(--p-brand-text); text-decoration: none; }
.pub-actions { display: flex; align-items: center; gap: .6rem; }
/* The language links — app/langs.py. Each name in its own script, so they are
   text, not a select: a visitor who cannot read Hebrew can still find theirs. */
.pub-langs { display: flex; flex-wrap: wrap; gap: .15rem .6rem; font-size: 13px; }
.pub-langs a { color: var(--p-ink-3); }
.pub-langs a[aria-current] { color: var(--p-ink); font-weight: 600; }
.pub-lang-notice {
  margin: 0; padding: .5rem 1rem; text-align: center; font-size: 13px;
  background: var(--p-soft, #f4f6f8); color: var(--p-ink); border-block-end: 1px solid var(--p-line);
}
/* The college's button: solid navy, white, 7px. Its outlined variant is the
   same shape with the fill taken out, which is what .pub-btn is here — the
   secondary action — while .pub-btn-solid is the primary. Measured: padding
   8px 27px 10px at 17px, which is the .62rem/1.5rem below at our 13px. */
.pub-btn {
  display: inline-block; padding: .62rem 1.5rem; font-size: 15px; font-weight: 500;
  letter-spacing: 0; border: 1px solid var(--p-ink); color: var(--p-ink); background: none;
  border-radius: var(--p-radius-btn);
}
.pub-btn:hover { background: var(--p-ink); color: var(--p-paper); text-decoration: none; }
.pub-btn-solid { background: var(--p-brand-text); border-color: var(--p-brand-text); color: var(--p-paper); }
.pub-btn-solid:hover { background: var(--p-ink); border-color: var(--p-ink); color: var(--p-paper); }

/* ---- recall ticker ---- */
.pub-recall { display: flex; align-items: stretch; background: var(--p-ink); color: var(--p-paper); overflow: hidden; }
.pub-recall-tag {
  flex: none; display: inline-flex; align-items: center; gap: .5rem;
  padding: .6rem 1.1rem; background: var(--p-red);
  font-family: var(--p-mono); font-size: 11px; font-weight: 700; letter-spacing: .14em;
}
.pub-recall-tag .dot { inline-size: 6px; block-size: 6px; border-radius: 50%; background: currentColor; animation: igapulse 2s ease-in-out infinite; }
.pub-recall-track { flex: 1; overflow: hidden; display: flex; align-items: center; }
.pub-recall-run { display: flex; gap: 2.4rem; white-space: nowrap; animation: igaticker 42s linear infinite; }
.pub-recall-run:hover { animation-play-state: paused; }
/* The stop control. `~` reaches the track because the checkbox is printed as a
   sibling before it — that ordering is load-bearing, do not move the input. */
.pub-recall-stop:checked ~ .pub-recall-track .pub-recall-run { animation-play-state: paused; }
.pub-recall-btn {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  inline-size: 34px; min-block-size: 24px; cursor: pointer;
  border-inline-end: 1px solid var(--p-line-dark); color: var(--p-paper);
  margin-block-end: 0; /* undoes the global `label { margin-block-end: .35rem }` */
}
.pub-recall-btn:hover { background: #0b3059; }
.pub-recall-btn .i::before { content: "\275A\275A"; font-size: 10px; letter-spacing: 1px; }
.pub-recall-stop:checked ~ .pub-recall-btn .i::before { content: "\25B6"; font-size: 11px; }
.pub-recall-stop:focus-visible ~ .pub-recall-btn { outline: 2px solid var(--p-brand-bright); outline-offset: -3px; }
.pub-recall-item { display: inline-flex; align-items: baseline; gap: .55rem; font-size: 12px; }
.pub-recall-item code { font-family: var(--p-mono); font-size: 11px; color: var(--p-brand-bright); }
.pub-recall-item span { color: #cfdae5; }
.pub-recall-all {
  flex: none; display: inline-flex; align-items: center; padding: .6rem 1.1rem;
  border-inline-start: 1px solid var(--p-line-dark); font-size: 11.5px; color: var(--p-brand-bright);
}
@media (prefers-reduced-motion: reduce) {
  .pub-recall-run { animation: none; }
  .pub-recall-tag .dot { animation: none; }
  /* nothing is moving, so a stop button would be a control that does nothing */
  .pub-recall-btn { display: none; }
}
.a11y-nomotion .pub-recall-btn { display: none; }

/* ---- hero ---- */
/* ⚠ FULL-BLEED, CENTRED, WHITE ON THE PICTURE — the college's hero, not the
   export's split. It was `grid-template-columns: 1fr 1fr` with the art in one
   half; carcollege.co.il runs the media edge to edge and centres the whole
   block of words over it. The academies' own hero (.pub-brand-hero) has always
   been this shape, and it is the one the association now wears too. */
.pub-hero { position: relative; display: grid; place-items: center;
  min-block-size: 72vh; background: var(--p-ink); overflow: hidden; }
/* The art is the ground. It is FIRST in the source and absolutely placed, so
   the copy paints over it with one z-index and no stacking context to unpick. */
.pub-hero-art { position: absolute; inset: 0; margin: 0;
  background: var(--p-ink); overflow: hidden; }
.pub-hero-art img { inline-size: 100%; block-size: 100%; object-fit: cover;
  /* ⚠ 30%, NOT CENTRE. A hero box far wider than a 3:2 photograph must lose top
     and bottom, and the only question is which part survives; anchoring above
     centre keeps a person's head in frame. The same decision, for the same
     reason, as the academy hero's video. */
  object-position: 50% 30%;
  /* ⚠ .35 IS MEASURED, NOT PICKED. White has to clear 4.5:1 over the BRIGHTEST
     frame the picture could possibly be, because a hero that reads only on a
     dark photograph reads on none. Composited over #082646 at .35 a pure-white
     frame lands at rgb(94,114,135), where white is 4.96:1 — so even the lead
     paragraph, which is small text, is clear. At .45 it is 3.65:1 and only the
     headline would pass. */
  opacity: .35; }
.pub-hero-art::after {
  content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(135deg, rgba(255,255,255,.022) 0 2px, transparent 2px 9px);
}
.pub-hero-art figcaption {
  position: absolute; inset-block-end: 1.2rem; inset-inline-start: 1.4rem; z-index: 1;
  font-family: var(--p-mono); font-size: 11px; color: var(--p-faint);
}
.pub-hero-body { position: relative; z-index: 2; color: var(--p-paper);
  display: flex; flex-direction: column; align-items: center; text-align: center;
  justify-content: center; gap: 1.1rem; padding: 5rem 2rem;
  max-inline-size: 62ch; margin-inline: auto; }
.pub-eyebrow {
  align-self: center; background: rgb(255 255 255 / .16); color: var(--p-paper);
  padding: .3rem .7rem; font-size: 11.5px; font-weight: 700; letter-spacing: -.01em;
  border-radius: var(--p-radius-btn);
}
/* The original sets 60px/54px at weight 700. The clamp keeps that as the
   ceiling and lets it fall to 30px on a phone; the line-height is the
   original's ratio (0.9) eased to 1.05, because Hebrew at 0.9 collides with
   its own descenders where Latin does not. */
.pub-hero-body h1 { font-size: clamp(30px, 5vw, 60px); font-weight: 700; line-height: 1.05; letter-spacing: -.03em; margin: 0; }
.pub-hero-body p { color: var(--p-paper); font-size: 17px; margin: 0; line-height: 1.7; }
/* Four buttons of one width in one row (Rami, 28.9.2026: a Facebook button
   wrapping alone under three read as misaligned). The row is wider than the
   62ch text above it on purpose, and falls to two by two on a phone. */
.pub-hero-cta { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .7rem;
  inline-size: min(860px, calc(100vw - 2rem)); margin-block-start: .6rem; }
.pub-hero-cta .pub-btn { text-align: center; padding-inline: .75rem; }
@media (max-width: 640px) { .pub-hero-cta { grid-template-columns: repeat(2, minmax(0, 1fr)); inline-size: 100%; } }
/* On the picture the outlined button is white-on-nothing; .pub-btn's base rule
   draws it in the ink, which would be a navy outline on a navy photograph. */
.pub-hero .pub-btn { border-color: var(--p-paper); color: var(--p-paper); }
.pub-hero .pub-btn:hover { background: var(--p-paper); color: var(--p-ink); }
.pub-hero .pub-btn-solid { background: var(--p-paper); border-color: var(--p-paper); color: var(--p-ink); }
.pub-hero .pub-btn-solid:hover { background: var(--p-brand-bright); border-color: var(--p-brand-bright); color: var(--p-ink); }
.pub-hero-nav { display: flex; gap: .4rem; margin-block-start: 1.4rem; justify-content: center; }
.pub-hero-nav button {
  inline-size: 34px; block-size: 34px; border: 1px solid rgb(255 255 255 / .45);
  background: none; color: var(--p-paper); font-size: 15px; line-height: 1;
  border-radius: var(--p-radius-btn);
}
.pub-hero-nav button:hover { border-color: var(--p-paper); background: rgb(255 255 255 / .14); }

/* ---- section scaffolding ---- */
.pub-sec { padding: 4.2rem 2rem; max-inline-size: 1240px; margin-inline: auto; }
/* ⚠ CENTRED, WHICH IS THE COLLEGE'S RHYTHM AND NOT THE EXPORT'S. Every section
   on carcollege.co.il announces itself in the middle of the measure — heading,
   then the one link out under it — where the export ran the heading along the
   start edge with the link pushed to the far end by an auto margin. The auto
   margin on .pub-more is what has to go with it: in a column it would shove the
   label to the inline edge and undo the centring. */
.pub-sec-head { display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: .8rem; margin-block-end: 2.4rem; }
/* ⚠ NO LONGER MONO, AND NO LONGER NUMBERED. This was «00 / שירותים מקוונים»
   in JetBrains Mono at 11px with .16em of tracking — the old export's
   signature, and the loudest thing on the page that belonged to neither this
   site nor the college's. carcollege.co.il has nothing of the kind: its
   sections are announced by a plain Hebrew phrase in the body face. The
   numbers came off the five home-page sections and the ABOUT/ACADEMY/LEGAL
   prefixes off the three inner ones in the same change; the three bare Latin
   words on the academies' front page (COURSES, TRACKS, FAQ) went entirely,
   because each repeated the heading directly under it in a language the site
   is not written in.

   With the digits gone the bidi isolation is no longer load-bearing — but it
   stays, because the content is a translated string and nothing stops a
   future one carrying a year or a number. Cheap, and the failure it prevents
   (a Latin run reordering itself against Hebrew) is the one this file has
   already had twice. */
.pub-idx { font-family: inherit; font-size: 14px; font-weight: 600; letter-spacing: 0;
  color: var(--p-muted); display: block; margin-block-end: .5rem;
  unicode-bidi: isolate; }
/* The college sets its section headings at 40px/700. The clamp reaches that
   as its ceiling now (it stopped at 34), and the weight drops from 900 to 700
   with the tracking loosened from -.04em to -.02em — the export ran heavy and
   very tight, which is the other half of what made the two sites read as
   different design systems rather than as one family. */
.pub-sec-head :is(h1, h2) { font-size: clamp(26px, 3.2vw, 40px); font-weight: 700; letter-spacing: -.02em; margin: 0; line-height: 1.15; }
.pub-more { font-size: 15px; font-weight: 600; color: var(--p-brand-text); white-space: nowrap; }
/* ⚠ THE HAIRLINES ARE DRAWN BY THE CELLS, NOT BY A BACKGROUND SHOWING THROUGH.
   This grid used `background: var(--p-line)` with `gap: 1px`, which draws the
   lines beautifully while every row is full — and paints a SOLID GREY BLOCK
   over the empty tail of the last row when the count is not a multiple of the
   column count. It reads as a broken card, not as absence.
   Live on 7.9.2026, before anything was changed: /about had 8 cards in a
   3-column grid (one grey cell), /info 4 (two), /certificates 2 (one). It was
   invisible on /services only because that page happened to carry exactly 9.
   Dropping it to Arie's seven made it obvious, which is the only reason it was
   found — nobody counts cards.
   Each cell now paints its own 1px ring, which exactly fills the 1px gap
   between two neighbours. Where there is no cell there is no ink.
   And NO CONTAINER BORDER either: a border on the GRID frames the empty tail
   as neatly as the background filled it. With the ring on each cell the outer
   edge is drawn by the cells themselves, so a short last row simply ends. */
/* ⚠ A REAL GAP, NOT A 1px HAIRLINE. The export butted its cards together and
   let a 1px gap read as a rule between them; the college separates rounded
   cards by about 22px of the page's own ground. The rounding is what forces it
   — two 20px-rounded cards 1px apart leave four white notches where their
   corners meet, which reads as a rendering fault. */
.pub-grid { display: grid; gap: 22px; }
.pub-grid-3 { grid-template-columns: repeat(3, 1fr); }
.pub-grid-2 { grid-template-columns: repeat(2, 1fr); }
.pub-grid-4 { grid-template-columns: repeat(4, 1fr); }

/* ⚠ AND FOUR, WHICH WAS MISSING AND IS WHY THE COLLEGE'S PANELS STACKED.
   pub_brand_home.html asks for `pub-grid-4` whenever a brand supplies four or
   more boxes; no such rule existed, so the grid fell back to ONE implicit
   column and the college's four "why study here" panels rendered as four
   full-width bands — a 62px icon centred in a 1,900px row with a line of text
   running the whole measure under it. Reported 8.9.2026 as "would it be nicer
   sideways?", which it would have been, and the answer is that it was never
   meant to be a column at all. */

/* THE COLLEGE'S CARD, measured: background #eff4f6, 20px radius, a 5px rule
   along the bottom edge drawn as an inset shadow, padding 19px 10px 20px.
   The rule is an inset box-shadow rather than a border-bottom on purpose — a
   border would sit outside the radius and square off the two bottom corners. */
.pub-cell { background: var(--p-wash); padding: 1.6rem; display: flex; flex-direction: column; gap: .55rem;
  border-radius: var(--p-radius);
  /* The news card's picture is INSET by the card's own padding, not bled to
     its edge, so it needs no clipping — it is given the button radius instead,
     a smaller curve inside a larger one. */
  box-shadow: inset 0 -5px 0 0 var(--p-rule); }
/* ⚠ THE RULE CYCLES, AND THE CYCLE IS THE DESIGN. The original runs green,
   amber, blue across a row and starts again — three cards, three colours, so a
   row reads as three things rather than as one striped block. Every one of the
   three is a NON-TEXT mark (all three fail 4.5:1 on the tint and none carries a
   word), which is the only reason they may be this bright; see the .pub block. */
.pub-cell:nth-child(3n+1) { box-shadow: inset 0 -5px 0 0 #0a7c4c; }
.pub-cell:nth-child(3n+2) { box-shadow: inset 0 -5px 0 0 var(--p-brand-bright); }
.pub-cell:nth-child(3n)   { box-shadow: inset 0 -5px 0 0 var(--p-rule); }
.pub-cell:hover { background: #e6edf1; }
/* The tag is a WORD — «פרונטלי», «הסמכה» — not a code, so it leaves the mono
   face with the kickers. JetBrains Mono stays where the file has always said
   it belongs: allocation numbers, garage numbers, figures. A Hebrew label at
   10.5px with .12em of tracking was the export's voice, and it is the same
   thing that made .pub-idx read as a different design system. */
.pub-tag {
  align-self: flex-start; font-family: inherit; font-size: 12.5px; font-weight: 500; letter-spacing: 0;
  color: var(--p-brand-text); background: rgb(8 38 70 / .07); padding: .25rem .6rem;
  border-radius: var(--p-radius-btn);
}
.pub-cell h3 { font-size: 17px; font-weight: 700; letter-spacing: -.015em; margin: 0; }
.pub-cell p { font-size: 15px; color: var(--p-muted); margin: 0; line-height: 1.7; }
.pub-cell > img { border-radius: var(--p-radius-btn); }
.pub-meta { display: flex; flex-wrap: wrap; gap: .35rem 1rem; font-size: 12px; color: var(--p-ink-3); }
.pub-meta i { font-style: normal; color: var(--p-brand-text); }

/* the no-login tools strip. .pub-more carries margin-inline-start:auto for the
   section headers, where it is a flex ROW; inside a cell the flex axis is the
   block one, so that auto margin would shove the label to the inline edge. */
.pub-tools-note { font-size: 15px; color: var(--p-muted); margin: .5rem 0 0; line-height: 1.7; }
.pub-tools-go { margin-inline-start: 0; margin-block-start: auto; padding-block-start: .5rem; }
.pub-dark .pub-tools-note { color: var(--p-faint); }

/* course price split — member vs not */
.pub-price { display: grid; grid-template-columns: 1fr 1fr; margin-block-start: auto; border-block-start: 1px solid var(--p-line); }
.pub-price div { padding: .7rem 0 0; }
.pub-price div + div { border-inline-start: 1px solid var(--p-line); padding-inline-start: .9rem; }
.pub-price small { display: block; font-size: 11px; color: var(--p-muted); }
.pub-price b { font-family: var(--p-mono); font-size: 15px; font-weight: 700; }
.pub-price .member b { color: var(--p-brand-text); }

/* ---- stats strip ---- */
.pub-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; }
.pub-stat { background: var(--p-wash); padding: 1.5rem; border-radius: var(--p-radius);
  box-shadow: inset 0 -5px 0 0 var(--p-rule); }
.pub-stat b { display: block; font-family: var(--p-mono); font-size: 30px; font-weight: 700; letter-spacing: -.04em; color: var(--p-brand-text); }
.pub-stat span { font-size: 12px; color: var(--p-muted); }

/* ---- branches ---- */
.pub-branch { background: var(--p-wash); padding: 1.5rem; display: flex; flex-direction: column; gap: .4rem;
  border-radius: var(--p-radius); }
.pub-branch code { font-family: var(--p-mono); font-size: 11px; letter-spacing: .12em; color: var(--p-brand-text); }
.pub-branch h3 { font-size: 15.5px; font-weight: 800; letter-spacing: -.02em; margin: 0; }
.pub-branch p { font-size: 12.5px; color: var(--p-muted); margin: 0; line-height: 1.55; }
.pub-branch .n { margin-block-start: auto; font-family: var(--p-mono); font-size: 12px; color: var(--p-ink-3); }

/* ---- dark band (membership) ---- */
.pub-dark { background: var(--p-ink); color: var(--p-paper); }
.pub-dark .pub-sec-head :is(h1, h2) { color: var(--p-paper); }
.pub-dark .pub-cell, .pub-dark .pub-stat { background: var(--p-ink-2);
  box-shadow: inset 0 -5px 0 0 var(--p-brand-bright); }
.pub-dark .pub-cell:hover { background: var(--p-ink-2); }
.pub-dark .pub-cell h3 { color: var(--p-paper); }
.pub-dark .pub-cell p, .pub-dark .pub-stat span { color: var(--p-faint); }
/* The figures on the dark band. --p-brand is the navy, and navy on near-black
   is 1.25:1 — the bright variant is what the dark surfaces are for. The green
   this replaced happened to be light enough to survive here, so the rule was
   never exercised on this element; the swap exercised it immediately. Caught by
   the axe run, not by the token arithmetic, which passed. */
.pub-dark .pub-stat b { color: var(--p-brand-bright); }
.pub-dark .pub-lead { color: #cfdae5; }

/* ---- footer ---- */
/* ⚠ THE TINT, NOT A DARK BAND. carcollege.co.il ends on #eff4f6 with its navy
   still the text colour — four branch columns and one centred legal line. The
   export ended on near-black, and a dark footer under a light page is the one
   place the two designs could not both be right. Light means --p-faint (a
   dark-surface token) may not carry a word down here; every link is the ink. */
.pub-foot { background: var(--p-wash); color: var(--p-ink-3); padding: 3rem 2rem 1.6rem;
  border-block-start: 1px solid var(--p-line); }
.pub-foot-in { max-inline-size: 1240px; margin-inline: auto; display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 2.5rem; }
.pub-foot .pub-foot-h { font-family: var(--p-mono); font-size: 11px; letter-spacing: .14em; color: var(--p-ink); margin: 0 0 .9rem; font-weight: 600; }
.pub-foot a { display: block; color: var(--p-ink-3); font-size: 13px; padding-block: .25rem; }
.pub-foot a:hover { color: var(--p-brand-text); text-decoration: underline; }
.pub-foot-bar {
  /* align-items, not the default stretch: this row mixes bare spans with
     links, and the links carry .pub-foot a's block padding plus a 24px minimum
     target size. Stretched, every item was the same height but the links' text
     started 4px below the copyright line — visibly off, and the taller the
     visitor sets the text, the wider the gap. */
  max-inline-size: 1240px; margin: 2.4rem auto 0; padding-block-start: 1.2rem;
  border-block-start: 1px solid var(--p-line-2); display: flex; gap: 1.2rem; flex-wrap: wrap;
  align-items: center; font-size: 12px;
}
.pub-foot-bar .sp { margin-inline-start: auto; }

/* ---- reveal ---- */
.pub-rise { animation: igarise .5s ease both; }
@media (prefers-reduced-motion: reduce) { .pub-rise { animation: none; } }

@media (max-width: 980px) {
  /* A phone's 100vh includes browser chrome that comes and goes, so the hero
     is pinned shorter here rather than left at 72vh. */
  .pub-hero { min-block-size: 68vh; }
  /* A phone's 100vh includes browser chrome that comes and goes; a shorter
     fixed height keeps the copy visible without the box resizing mid-scroll. */
  .pub-brand-hero { min-block-size: 68vh; }
  .pub-grid-3, .pub-grid-4, .pub-stats { grid-template-columns: repeat(2, 1fr); }
  /* ⚠ FOLDED BEHIND A BUTTON, NOT DELETED. This was a bare `display: none`
     with no toggle anywhere in the repo, so every phone and tablet visitor had
     no navigation at all — see .pub-navtoggle. */
  .pub-nav { display: none; }
  .pub-nav[data-open="1"] {
    display: flex; position: absolute; inset-inline: 0; top: 100%;
    flex-direction: column; gap: 0; margin: 0; padding: .6rem 1.2rem 1rem;
    background: var(--p-paper); border-block-end: 1px solid var(--p-line);
    box-shadow: 0 12px 24px rgb(11 18 17 / .10); z-index: 40;
    max-block-size: 70vh; overflow-y: auto; }
  .pub-nav[data-open="1"] .pub-navgroup { inline-size: 100%; }
  .pub-nav[data-open="1"] .pub-navgroup > a { display: block; padding-block: .7rem; }
  /* the dropdown panels stack inline rather than hovering */
  /* ⚠ transform: none IS THE LINE THAT MAKES THIS VISIBLE. The desktop panel is
     centred under its parent with `translateX(50%)`; going `position: static`
     does not cancel a transform, so each submenu still shifted half its width
     sideways and rendered off the panel — every dropdown was a tall band of
     blank space with its links pushed out of view. The menu opened, looked
     broken, and the links were there the whole time. */
  .pub-nav[data-open="1"] .pub-submenu {
    position: static; transform: none; visibility: visible; opacity: 1;
    box-shadow: none; border: 0; padding: 0 0 .4rem; min-inline-size: 0;
    inline-size: 100%; }
  .pub-nav[data-open="1"] .pub-submenu a { padding-inline-start: 1.1rem; }
  /* (the toggle is revealed at the END of this file, after its base rule —
      see the note there; a reveal placed HERE loses the cascade.) */
  .pub-foot-in { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 620px) {
  .pub-grid-4, .pub-grid-3, .pub-grid-2, .pub-stats { grid-template-columns: 1fr; }
  .pub-status .since { display: none; }
  .pub-sec { padding: 2.6rem 1.2rem; }
  .pub-head, .pub-status { padding-inline: 1.2rem; }
}

/* Keyframes carried over from the design export, verbatim. igaticker moves the
   run by exactly 50% because the strip renders its items TWICE — that is what
   makes the loop seamless; changing either number alone makes it jump. */
@keyframes igapulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .3; transform: scale(.8); } }
@keyframes igaticker { from { transform: translateX(0); } to { transform: translateX(50%); } }
@keyframes igarise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }

/* ---- public garage directory ---- */
.dir-filters { display: flex; flex-wrap: wrap; gap: .8rem; align-items: flex-end;
  background: var(--p-wash); border: 1px solid var(--p-line); padding: 1rem 1.1rem; }
/* Sits above the filter row: WCAG 3.2.2 wants the notice BEFORE the control it
   describes, not after it has already reloaded the page. */
.dir-auto { font-size: 12px; color: var(--p-muted); margin-block-end: .45rem; }
/* margin-block-end: 0 undoes the global `label` rule. The fields are <label>
   elements and the actions group is a <div>; under align-items:flex-end it is
   the MARGIN box that aligns, so the labels sat exactly .35rem — 5.6px — above
   the buttons. That was the whole of the "not aligned", and no amount of
   matching heights would have fixed it. */
.dir-field { display: flex; flex-direction: column; gap: .3rem; font-size: 12px;
  color: var(--p-muted); margin-block-end: 0; }
/* Getting these four controls onto one line took three goes. What finally
   works, and why the earlier attempts did not:

   1. The selects measured 46.4px against the inputs' 40px, and `block-size`
      would not move them. The cause was not the <select> at all: this
      stylesheet's own form rule sets `min-block-size: 2.9rem` on every input
      and select — a deliberate touch-target size for the members' app. So the
      controls are sized TO that 2.9rem rather than fighting it down to 40px;
      one number, and the public site matches the app's own control height.
      `appearance: none` still applies so the chevron is ours and consistent.
   2. `display: inline-flex` on a <select> is meaningless (it is a replaced
      element) and was doing nothing but hiding the real cause.
   3. align-items:flex-end could not save it either, because the buttons are
      bare flex children while the selects sit under a label. The buttons ended
      6px below the fields. They now live in a .dir-field of their own with a
      spacer where the label goes, so every child has the same structure and
      the bottoms line up by construction rather than by arithmetic. */
.dir-field input, .dir-field select, .dir-btns .pub-btn {
  block-size: 2.9rem; box-sizing: border-box; padding-block: 0;
  font: inherit; font-size: 13.5px; line-height: 1;
}
.dir-field input, .dir-field select {
  padding-inline: .6rem; min-inline-size: 190px;
  border: 1px solid var(--p-line); background: var(--p-paper); color: var(--p-ink);
}
.dir-field select {
  appearance: none; -webkit-appearance: none; padding-inline-end: 2rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%236b7a77' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-size: 11px; background-position: left .7rem center;
}
.dir-actions > span { visibility: hidden; }      /* label-height spacer */
/* The fields SHARE the row instead of sizing to content. A <select> is as wide
   as its longest option, so the unfiltered town list pushed סינון/ניקוי onto a
   second line, and they only returned to the row (on the left, RTL end) once a
   filter had narrowed the options — the same page in two layouts (24.9.2026). */
.dir-filters > .dir-field { flex: 1 1 190px; min-inline-size: 0; }
.dir-filters > .dir-field input, .dir-filters > .dir-field select { inline-size: 100%; min-inline-size: 0; }
.dir-filters > .dir-actions { flex: none; }
.dir-btns { display: flex; gap: .6rem; }
.dir-btns .pub-btn { display: inline-flex; align-items: center; }
.dir-field input:focus-visible, .dir-field select:focus-visible {
  outline: 2px solid var(--p-brand); outline-offset: 1px;
}
.dir-count { margin: 1rem 0 1.2rem; font-size: 13px; color: var(--p-muted); }
.dir-contact { margin-block-start: auto; display: flex; flex-direction: column; gap: .2rem;
  font-size: 12.5px; color: var(--p-muted); padding-block-start: .6rem; }
.dir-contact a { color: var(--p-brand-text); }
.dir-pager { display: flex; gap: 1rem; align-items: center; justify-content: center;
  margin-block-start: 1.8rem; font-size: 13px; color: var(--p-muted); }
.dir-empty { padding: 2rem; background: var(--p-wash); border: 1px solid var(--p-line);
  font-size: 14px; color: var(--p-ink-3); }
@media (max-width: 620px) { .dir-field input, .dir-field select { min-inline-size: 0; inline-size: 100%; }
  .dir-field { inline-size: 100%; } }

/* ---- about page ---- */
.about-lead { max-inline-size: 74ch; display: flex; flex-direction: column; gap: 1rem; }
.about-lead p { font-size: 15.5px; line-height: 1.85; color: var(--p-ink-3); }

/* ---- regulation hub ---- */
.reg-table-wrap { overflow-x: auto; border: 1px solid var(--p-line); margin-block-start: 1.4rem; }
.reg-table { inline-size: 100%; border-collapse: collapse; font-size: 13.5px; background: var(--p-paper); }
.reg-table th, .reg-table td { text-align: start; padding: .8rem 1rem; border-block-end: 1px solid var(--p-line); }
.reg-table thead th { font-family: var(--p-mono); font-size: 10.5px; letter-spacing: .12em;
  color: var(--p-muted); font-weight: 600; background: var(--p-wash); }
.reg-table tbody tr:hover { background: var(--p-wash); }
.reg-table a { color: var(--p-brand-text); font-weight: 600; }
.reg-fmt { font-family: var(--p-mono); font-size: 10px; letter-spacing: .08em; color: var(--p-muted);
  border: 1px solid var(--p-line); padding: .1rem .35rem; margin-inline-end: .5rem; }
.reg-new { font-family: var(--p-mono); font-size: 10px; letter-spacing: .08em;
  background: var(--p-brand-text); color: var(--p-paper); padding: .1rem .4rem; margin-inline-start: .5rem; }
.reg-nolink { font-style: normal; font-size: 11.5px; color: var(--p-muted); margin-inline-start: .5rem; }
.acad-demo { background: rgb(8 38 70 / .06); border-inline-start: 3px solid var(--p-brand);
  padding: .8rem 1rem; font-size: 13px; color: var(--p-ink-3); margin-block-end: 1.2rem; }

/* ---- public site: keyboard access ----
   A skip link is the one thing a keyboard user needs first and the one thing a
   redesign forgets: without it, reaching the content past a masthead, a five-item
   nav and a recall ticker is a dozen tabs on every page. Visible only on focus. */
.pub-skip {
  position: absolute; inset-block-start: -100px; inset-inline-start: 0; z-index: 100;
  background: var(--p-ink); color: var(--p-paper); padding: .7rem 1.2rem;
  font-size: 14px; font-weight: 700;
}
.pub-skip:focus { inset-block-start: 0; text-decoration: none; }
/* Every interactive thing on the public site shows focus. The default outline
   disappears against the dark bands, so it is drawn in the bright green there. */
.pub a:focus-visible, .pub button:focus-visible, .pub input:focus-visible,
.pub select:focus-visible, .pub .pub-btn:focus-visible {
  outline: 2px solid var(--p-brand-text); outline-offset: 2px;
}
/* ⚠ THE LIST IS THE DARK SURFACES, AND TWO OF THEM CHANGED ON 15.9.2026.
   .pub-hero JOINED: it used to be a split with the words on paper, and it is
   now a full-bleed picture on the ink, so the carousel arrows, the pause button
   and both CTAs were drawing a navy focus ring on a navy ground — no visible
   focus at all for a keyboard user, on the first thing they reach.
   .pub-foot LEFT: it took the college's tint, and the amber that makes a ring
   visible on the ink is 1.75:1 on that, which is the same defect the other way
   round. Adding one and forgetting the other would have been the whole bug
   again, so they move in one edit.
   The test above this cannot catch either — it asserts the two selector strings
   exist, not that the list matches the set of dark surfaces. */
.pub-dark a:focus-visible, .pub-dark button:focus-visible,
.pub-status a:focus-visible, .pub-recall a:focus-visible,
.pub-hero a:focus-visible, .pub-hero button:focus-visible {
  outline-color: var(--p-brand-bright);
}
.a11y-list { margin-inline-start: 1.2rem; max-inline-size: 76ch; }
.a11y-list li { font-size: 14px; line-height: 1.85; color: var(--p-ink-3); margin-block-end: .5rem; }
.a11y-gaps li::marker { color: var(--p-muted); }

/* ============================================================================
   תפריט נגישות — every setting is a class on <html>; the CSS does the work.
   Self-hosted: no vendor script, no per-domain licence, and nothing that can
   switch itself off when a traffic quota is exceeded.

   This adjusts PRESENTATION. Conformance to ת"י 5568 lives in the markup and is
   verified by an auditor — see /accessibility, which is careful about the
   difference. Nothing here should be read as a conformance claim.
   ============================================================================ */
.a11y-fab {
  position: fixed; inset-block-end: 22px; inset-inline-start: 22px; z-index: 90;
  inline-size: 52px; block-size: 52px; border-radius: 50%;
  background: var(--p-ink, #0b1211); color: #fff; border: 2px solid #fff;
  box-shadow: 0 4px 18px rgba(0,0,0,.35); display: grid; place-items: center;
  cursor: pointer; padding: 0;
}
.a11y-fab:hover, .a11y-fab:focus-visible { background: var(--p-brand-text, #0a7c4c); }
.a11y-fab svg { inline-size: 26px; block-size: 26px; }

.a11y-panel {
  position: fixed; inset-block-end: 86px; inset-inline-start: 22px; z-index: 91;
  inline-size: min(360px, calc(100vw - 44px)); max-block-size: min(74vh, 640px);
  overflow-y: auto; background: #fff; color: #0b1211;
  border: 1px solid #d7dedc; box-shadow: 0 16px 48px rgba(0,0,0,.28);
}
.a11y-head {
  display: flex; align-items: center; gap: .6rem; padding: .9rem 1rem;
  background: var(--p-ink, #0b1211); color: #fff; position: sticky; inset-block-start: 0;
}
.a11y-head h2 { font-size: 15px; font-weight: 800; margin: 0; }
.a11y-head button {
  margin-inline-start: auto; background: none; border: 1px solid rgba(255,255,255,.4);
  color: #fff; inline-size: 30px; block-size: 30px; font-size: 16px; line-height: 1; cursor: pointer;
}
.a11y-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; padding: 10px; }
.a11y-grid button {
  display: flex; flex-direction: column; align-items: center; gap: .35rem;
  padding: .7rem .3rem; background: #fff; border: 1px solid #dfe5e3;
  font-size: 11px; font-weight: 600; color: #1e2b28; cursor: pointer; text-align: center;
  min-block-size: 74px; justify-content: center;
}
.a11y-grid button:hover { border-color: var(--p-brand-text, #0a7c4c); }
.a11y-grid button[aria-pressed="true"] {
  border-color: var(--p-brand-text, #0a7c4c); background: rgba(10,124,76,.10);
  color: var(--p-brand-text, #0a7c4c);
}
.a11y-grid svg { inline-size: 22px; block-size: 22px; }
.a11y-foot {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .8rem 1rem; border-block-start: 1px solid #e6ebe9;
}
.a11y-foot a { color: var(--p-brand-text, #0a7c4c); font-size: 12.5px; font-weight: 600; }
.a11y-foot button {
  margin-inline-start: auto; background: none; border: 1px solid #c0392b; color: #c0392b;
  padding: .45rem .9rem; font-size: 12.5px; font-weight: 700; cursor: pointer;
}
.a11y-note { padding: 0 1rem .9rem; font-size: 11.5px; color: #5f6e6b; line-height: 1.6; }

/* the panel must never be recoloured by the visitor's own colour setting, or
   the control they need to undo it becomes unreadable */
.a11y-invert .a11y-panel, .a11y-invert .a11y-fab { filter: invert(1); }
.a11y-mono .a11y-panel, .a11y-mono .a11y-fab,
.a11y-sepia .a11y-panel, .a11y-sepia .a11y-fab { filter: none; }

/* ---- the settings ---- */
.a11y-contrast body { background: #000 !important; }
.a11y-contrast body :not(.a11y-panel):not(.a11y-panel *):not(.a11y-fab):not(.a11y-fab *) {
  background-color: transparent !important; color: #fff !important; border-color: #fff !important;
}
.a11y-contrast body a:not(.a11y-panel *) { color: #ff0 !important; text-decoration: underline !important; }

.a11y-invert body { filter: invert(1) hue-rotate(180deg); }
.a11y-mono body { filter: grayscale(1); }
.a11y-sepia body { filter: sepia(.85); }
.a11y-blackyellow body { background: #000 !important; }
.a11y-blackyellow body :not(.a11y-panel):not(.a11y-panel *):not(.a11y-fab):not(.a11y-fab *) {
  background-color: transparent !important; color: #ff0 !important; border-color: #ff0 !important;
}

.a11y-links a:not(.a11y-panel *) {
  text-decoration: underline !important; text-underline-offset: 3px;
  outline: 1px dashed currentColor; outline-offset: 2px;
}
.a11y-headings :is(h1,h2,h3,h4):not(.a11y-panel *) {
  outline: 2px solid var(--p-brand-text, #0a7c4c); outline-offset: 3px;
}
.a11y-readable body :not(.a11y-panel):not(.a11y-panel *) {
  font-family: Arial, "Helvetica Neue", sans-serif !important;
}
/* WCAG 1.4.12 Text Spacing — the values the success criterion itself names */
.a11y-spacing body :not(.a11y-panel):not(.a11y-panel *) {
  line-height: 1.5 !important; letter-spacing: .12em !important; word-spacing: .16em !important;
}
.a11y-spacing p:not(.a11y-panel *) { margin-block-end: 2em !important; }

.a11y-font-1 body { font-size: 112%; }
.a11y-font-2 body { font-size: 125%; }
.a11y-font-3 body { font-size: 140%; }
.a11y-font-4 body { font-size: 160%; }
.a11y-zoom-1 body { zoom: 1.1; } .a11y-zoom-2 body { zoom: 1.25; } .a11y-zoom-3 body { zoom: 1.4; }

.a11y-cursor-big body { cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 24 24'%3E%3Cpath d='M5 2l14 8-6 1.6L10 20z' fill='%23fff' stroke='%23000' stroke-width='1.4'/%3E%3C/svg%3E") 4 4, auto; }
.a11y-cursor-black body { cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 24 24'%3E%3Cpath d='M5 2l14 8-6 1.6L10 20z' fill='%23000' stroke='%23fff' stroke-width='1.4'/%3E%3C/svg%3E") 4 4, auto; }

/* a stronger focus ring than the default, for someone driving by keyboard */
.a11y-kbd :is(a,button,input,select,textarea,[tabindex]):focus {
  outline: 4px solid #ff0 !important; outline-offset: 3px !important;
  box-shadow: 0 0 0 7px #000 !important;
}
/* Stops the recall ticker and every other animation. This is the manual control
   WCAG 2.2.2 asks for on moving content — prefers-reduced-motion covers the
   people who set it system-wide, not the ones who did not. */
.a11y-nomotion *, .a11y-nomotion *::before, .a11y-nomotion *::after {
  animation: none !important; transition: none !important; scroll-behavior: auto !important;
}
/* Surfaces the alt text of every image as visible copy under it. */
.a11y-alt img:not(.a11y-panel *) { outline: 1px solid var(--p-brand-text, #0a7c4c); }
.a11y-alt img[alt]:not([alt=""]):not(.a11y-panel *)::after {
  content: attr(alt); display: block; position: absolute;
  background: #0b1211; color: #fff; font-size: 11px; padding: .2rem .4rem; max-inline-size: 100%;
}
.a11y-guide-bar {
  position: fixed; inset-inline: 0; inset-block-start: 0; block-size: 40px; z-index: 89;
  border-block: 2px solid #0a7c4c; background: rgba(255,255,0,.10); pointer-events: none;
}
@media print { .a11y-fab, .a11y-panel, .a11y-guide-bar { display: none !important; } }

/* ---- dark band: the light-surface colours inverate their contrast ----
   axe found four failures that a token-level check cannot: --p-muted is 5.34:1
   on white but 3.54:1 on the ink, and --p-brand-text is tuned for white (5.25)
   yet only 3.60 on the ink. On the dark band the LIGHTER members of the family
   are the accessible ones — --p-faint reads 5.48:1 there and --p-brand-bright
   10.36:1. Checked in a browser with axe-core, not inferred. */
.pub-dark .pub-idx { color: var(--p-faint); }
.pub-dark .pub-more { color: var(--p-brand-bright); }
.pub-dark .pub-tag { color: var(--p-brand-bright); background: rgba(59,217,139,.12); }

/* Hit areas. The nav links, the "←" section links and the tel: links measured
   20-22px tall — width was never the problem, line-height was. WCAG 2.5.8 is
   2.2 AA and ת"י 5568 points at 2.0, so this is not required; it costs two
   rules and it is the difference between a comfortable tap and a missed one. */
.pub-nav a, .pub-more, .pub-foot a, .dir-contact a, .pub-sec p > a { display: inline-flex; align-items: center; min-block-size: 24px; }
.pub-recall-all, .a11y-foot a { min-block-size: 24px; display: inline-flex; align-items: center; }

/* ארכיון — Arie's three components as their own entrances */
.pub-kinds { display: flex; flex-wrap: wrap; gap: .5rem; margin-block: 1.2rem 0; }
.pub-kinds .n { font-family: var(--p-mono); font-size: 11px; opacity: .7; margin-inline-start: .35rem; }


/* archive — an issue's own pictures, shown as a set because the harvest did not
   record where each one sat in the article */
.pub-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
               gap: .6rem; margin-block: 1.4rem; }
.pub-gallery img { inline-size: 100%; block-size: 130px; object-fit: cover; display: block; }
.pub-gallery a:hover img { opacity: .88; }
@media (max-width: 600px) { .pub-gallery { grid-template-columns: repeat(2, 1fr); } }

.pub-sector-icon { inline-size: 46px; block-size: 46px; object-fit: contain;
                   margin-block-end: .5rem; align-self: flex-start; }

/* the hero picture, once the association's own is copied */
.pub-hero-art img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.pub-hero-art:has(img)::after { content: none; }

/* ---- the decisions form (/decisions) ------------------------------------- */
/* Wide on purpose: each item carries the context somebody needs to answer it
   cold, and that prose should not be read through a narrow gutter. */
.dec-wrap { max-width: 1400px; margin-inline: auto; }
.dec-lede { color: var(--p-ink-3); max-width: 100ch; font-size: 16px; }
.dec-who { background: var(--p-soft, #f7f9fb); border: 1px solid var(--line, #d7dde5);
  padding: 14px 18px; margin: 18px 0 26px; display: flex; gap: 14px;
  align-items: center; flex-wrap: wrap; }
.dec-who input { padding: 8px 10px; min-inline-size: 260px; }
.dec-intro { color: var(--p-ink-3); max-width: 100ch; padding-block-end: 10px;
  border-block-end: 1px solid var(--line, #d7dde5); }
.dec-item { display: flex; gap: 24px; border: 1px solid var(--line, #d7dde5);
  border-inline-start: 4px solid var(--line, #d7dde5); padding: 16px 20px;
  margin: 12px 0; align-items: flex-start; }
.dec-now  { border-inline-start-color: var(--p-brand, #082646); background: #fbfcfe; }
.dec-ask  { border-inline-start-color: #8a5b00; background: #fdf8ef; }
.dec-stop { border-inline-start-color: #a3231f; background: #fdf3f2; }
.dec-q { flex: 1 1 auto; min-inline-size: 0; }
.dec-q h3 { margin: 0 0 6px; font-size: 17.5px; color: var(--p-brand, #082646); }
.dec-state { display: block; font-size: 12.5px; font-weight: 700;
  color: var(--p-muted, #6b7280); margin-block-end: 4px; }
.dec-ifno { font-size: 14.5px; color: var(--p-ink-3); margin-block-start: 10px;
  padding-block-start: 8px; border-block-start: 1px dashed var(--line, #d7dde5); }
.dec-choice { flex: 0 0 250px; }
.dec-radio { display: block; font-size: 14.5px; margin-block-end: 4px; cursor: pointer; }
.dec-choice textarea { inline-size: 100%; margin-block-start: 8px; padding: 8px;
  font-family: inherit; font-size: 14px; }
.dec-save { position: sticky; inset-block-end: 0; background: #fff;
  border-block-start: 2px solid var(--p-brand, #082646); padding: 14px 0;
  margin-block-start: 24px; display: flex; gap: 14px; align-items: center; flex-wrap: wrap; }
@media (max-width: 860px) {
  .dec-item { flex-direction: column; }
  .dec-choice { flex-basis: auto; inline-size: 100%; }
}
.dec-prod { border: 1px solid var(--line, #d7dde5); border-inline-start: 4px solid #6b7280;
  background: #f7f9fb; padding: 14px 20px; margin: 18px 0; }
.dec-prod h2 { margin: 0 0 6px; font-size: 16.5px; color: #3c434c; border: 0; padding: 0; }
.dec-prod p { margin: 0; max-inline-size: 105ch; color: var(--p-ink-3); font-size: 15px; }

/* ── THE ACADEMY BRANDS ──────────────────────────────────────────────────────
   carcollege.co.il and meisteracademy.co.il are served by this same app, keyed
   on the Host header (app/brands.py). Rami's instruction was "all visual
   similar with the needed changes", so a brand overrides the THREE tokens that
   carry colour and nothing else — every measurement in the .pub block above,
   including the contrast ratios tests/test_a11y.py recomputes, still holds.

   ⚠ COLOURS ARE MEASURED FROM EACH SITE'S OWN LIVE PAGES, not chosen here.
   Anything beyond "same style, different name and colour" is Arie's call. */

/* מייסטר — navy and gold, counted off its own live home page (#000064 twelve
   times, #cda04b eleven). Contrast measured, not assumed:
     navy on white 17.74:1 · navy on the wash 16.34:1  → carries text
     gold on white  2.41:1                             → NEVER text on light
     gold on the ink 7.87:1                            → the bright-on-dark accent
   which is exactly the split --p-brand-bright already documents. */
.brand-meister {
  --p-brand: #000064;
  --p-brand-text: #000064;
  --p-brand-bright: #cda04b;
}


/* ── AN ACADEMY'S FRONT PAGE ─────────────────────────────────────────────────
   The college's hero is a full-bleed background video with the headline over
   it; מייסטר's is the same shape with a photograph. Both were rendering as a
   column of paragraphs before this. The overlay is what keeps white text
   legible over a moving image — measured against the darkest frame, not the
   lightest, because a hero that reads only on the first frame reads on none. */
/* ⚠ THE FRAME FOLLOWS THE FOOTAGE, IT DOES NOT CROP IT. The film is 1920x1080
   (16:9) and a person's head is near the top of frame. Pinned to 72vh the box
   is far wider than 16:9 on any desktop, so object-fit:cover scaled to the
   WIDTH and cut the top off — the head. aspect-ratio makes the section's height
   follow its own width, so cover has nothing left to crop; the clamp keeps it
   from becoming a letterbox on an ultrawide or taller than the screen. The
   original sets calc(100vh - 90px), which is the same intent expressed as a
   height, and it does not crop because its content column is narrower. */
/* ⚠ ONE COLUMN, OVERRIDING .pub-hero. The element carries both classes, and
   .pub-hero is the ASSOCIATION's split hero — a 1fr 1fr grid with art on one
   side and copy on the other. Inherited here it put the copy in a half-width
   column over a full-width film, which is why the words looked boxed in. */
.pub-brand-hero { grid-template-columns: 1fr; position: relative;
  /* ⚠ FULL WIDTH AND FULL HEIGHT, WHICH IS WHAT THE ORIGINAL SETS:
     content_width "full" and min-height calc(100vh - 90px). An earlier fix
     here used aspect-ratio 16/9 to stop the film being cropped, and traded one
     fault for another — the video stopped being cut and started sitting in a
     letterbox narrower than the page, on a screen the original fills.
     THE CROP WAS NEVER THE HEIGHT'S FAULT. It is object-position: a 16:9 film
     in a wider-than-16:9 box must lose top and bottom, and the only question is
     WHICH part survives. Anchoring near the top keeps the heads in frame, which
     is what the complaint was actually about. */
  min-block-size: calc(100vh - 90px);
  /* ⚠ CENTRED, LIKE THE ORIGINAL. Sinking the copy to the bottom was a
     consequence of the scrim being a bottom gradient — the words had to sit
     where the dark was. Compared side by side with carcollege.co.il the
     original centres its block over the subject's chest, which is the calm
     part of the frame; at the bottom the headline lands across the car
     wireframe, the busiest thing in the picture. */
  display: grid; align-items: center; overflow: hidden; }
.pub-brand-hero .pub-hero-video {
  position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
  /* 25% keeps the subject's head inside the frame when the box is wider than
     the film's 16:9 and cover has to drop the top and bottom. */
  object-fit: cover; object-position: 50% 25%; z-index: 0; }
/* ⚠ THE SCRIM SITS BEHIND THE WORDS, NOT OVER THE FILM. A full-bleed gradient
   at .34-.62 was darkening the whole picture — and the ORIGINAL HAS NO OVERLAY
   AT ALL; it was invented here to keep white text legible and applied to the
   entire frame to do it. White text still needs a dark ground, so the ground is
   now only under the text: transparent at the top where the film plays clean,
   dark at the bottom where the words are, which is why the copy is aligned to
   the end of the box. */
/* ⚠ A SOFT POOL BEHIND THE COPY, NOT A BAND ACROSS THE PICTURE. The words are
   centred now, so the ground follows them: a radial wash densest where the text
   sits and clear at every edge, which keeps white legible over a moving image
   without dimming the film the way the first full-bleed gradient did. The
   original carries no overlay at all and gets away with it because its footage
   happens to be dark behind its text; ours must not depend on the frame. */
.pub-brand-hero::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: radial-gradient(ellipse 68% 46% at 50% 62%,
              rgb(11 18 17 / .58) 0%, rgb(11 18 17 / .34) 55%,
              rgb(11 18 17 / 0) 100%); }
.pub-hero-copy { position: relative; z-index: 2; text-align: center;
  padding: 2rem 1.4rem; margin-inline: auto; max-inline-size: 62ch;
  color: #fff; }
.pub-hero-copy h1 { color: #fff; margin: .3rem 0 .8rem; }
.pub-hero-copy p { color: rgb(255 255 255 / .93); font-size: 15.5px; line-height: 1.85; }
.pub-hero-copy .pub-idx { color: rgb(255 255 255 / .82); }
/* A logo replaces the "+" mark; the mark's own box sizing still applies. */
.pub-mark-img { object-fit: contain; background: none; }
/* /members while TECHNIGA is down: logo, one line, one way to reach a person */
.pub-soon { text-align: center; display: grid; justify-items: center; gap: 1rem; padding-block: 4rem; }
.pub-soon p { max-inline-size: 52ch; }
/* A block that is only a link — an Elementor button carried across. */
.pub-prose-cta { margin-block: .2rem 1.1rem; }


/* The academies' front-page components. */
.pub-brand-box { text-align: center; }
.pub-brand-icon { inline-size: 62px; block-size: 62px; object-fit: contain;
  margin: 0 auto .9rem; display: block; }
.pub-faq { max-inline-size: 78ch; }
.pub-faq details { border-block-end: 1px solid var(--p-line); }
.pub-faq summary { cursor: pointer; padding: .95rem .2rem; font-weight: 600;
  font-size: 15px; color: var(--p-ink); list-style: none; }
.pub-faq summary::-webkit-details-marker { display: none; }
/* The open/closed affordance is a rotating caret rather than the browser's
   default triangle, which sits on the wrong side in RTL. */
.pub-faq summary::after { content: "+"; float: inline-end; font-weight: 400;
  font-size: 19px; line-height: 1; color: var(--p-brand); }
.pub-faq details[open] summary::after { content: "–"; }
.pub-faq details p { margin: 0 0 1.1rem; padding-inline-start: .2rem;
  color: var(--p-ink-3); font-size: 14.5px; line-height: 1.85; }
.pub-logos { display: flex; flex-wrap: wrap; gap: 1.6rem 2.4rem;
  align-items: center; justify-content: center; }
.pub-logos img { block-size: 46px; inline-size: auto; object-fit: contain;
  /* The logos arrive in a dozen palettes; muting them to a common weight is
     what makes a row of them read as one strip rather than fourteen stickers.
     They return to full colour on hover. */
  filter: grayscale(1); opacity: .62; transition: filter .15s, opacity .15s; }
.pub-logos img:hover { filter: none; opacity: 1; }


/* Tables carried across from the academies' pages — fee schedules, admission
   criteria. `overflow-x:auto` on the WRAPPER so a wide table scrolls intact on
   a phone; the page itself never scrolls sideways and no cell is ever clipped. */
.pub-tablewrap { overflow-x: auto; margin-block: 1.1rem 1.6rem;
  max-inline-size: 100%; }
.pub-table { border-collapse: collapse; inline-size: 100%; min-inline-size: 32ch;
  font-size: 14.5px; }
.pub-table th, .pub-table td { border: 1px solid var(--p-line);
  padding: .6rem .8rem; text-align: start; vertical-align: top;
  line-height: 1.7; }
.pub-table th { background: var(--p-wash); font-weight: 600; color: var(--p-ink); }
.pub-table td { color: var(--p-ink-3); }


/* The academies' lead forms. */
.pub-enquiry { margin-block: 1.6rem 2rem; max-inline-size: 62ch;
  border: 1px solid var(--p-line); padding: 1.4rem 1.5rem; background: var(--p-wash); }
.pub-enquiry h3 { margin: 0 0 1rem; }
/* A long form that IS the page (עובדים זרים): the 62ch cap left it hugging
   the start edge beside half a page of nothing (Rami, 28.9.2026). It takes
   the page's measure, and .pub-fields spreads to two and three columns. */
.pub-enquiry.pub-enquiry-wide { max-inline-size: none; }
.pub-fields { display: grid; gap: .9rem 1.2rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
.pub-field-wide { grid-column: 1 / -1; }
.pub-field label { display: block; font-size: 13.5px; font-weight: 600;
  margin-block-end: .3rem; color: var(--p-ink); }
.pub-field input, .pub-field select, .pub-field textarea {
  inline-size: 100%; padding: .55rem .7rem; font: inherit; font-size: 14.5px;
  border: 1px solid var(--p-line); background: var(--p-paper); color: var(--p-ink); }
.pub-field input[type="checkbox"] { inline-size: auto; }
.pub-field :focus-visible { outline: 2px solid var(--p-brand); outline-offset: 1px; }
/* Off-screen rather than display:none — some bots skip hidden inputs. */
.pub-hp { position: absolute; inline-size: 1px; block-size: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ── The three imported-page templates ────────────────────────────────────────
   Course, regulations and editorial. Built from the same tokens as everything
   above — no new colours, no new type sizes that were not already in .pub-*.

   ⚠ EVERY GRID HERE COLLAPSES TO ONE COLUMN BEFORE ITS CONTENT CAN BE CUT. A
   facts strip of four figures at 320px would either clip a label or shrink a
   number out of legibility; a contents column beside a 74ch measure has no room
   to exist on a phone. The rule the whole site follows is that the LAYOUT
   changes and the content never does, so each of these has an explicit
   single-column state rather than relying on minmax() to be kind. */

.pub-standfirst {
  max-inline-size: 68ch; margin-block: 1rem 0;
  color: var(--p-ink-3); font-size: 16.5px; line-height: 1.8;
}
.pub-standfirst-lg { font-size: 19px; line-height: 1.75; color: var(--p-ink); font-weight: 500; }

/* The facts strip: the hours a student scans for. auto-fit rather than a fixed
   four, because the count is the course's own — 22 of the 25 give three
   figures plus the format, but some give one. */
.pub-facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px; background: var(--p-line); border: 1px solid var(--p-line);
  margin-block-start: 2.6rem;
}
.pub-fact { background: var(--p-wash); padding: 1.5rem 1.6rem; }
.pub-fact-n { font-family: var(--p-mono); font-size: 30px; font-weight: 600;
              color: var(--p-brand-text, var(--p-brand)); line-height: 1; }
.pub-fact-t { font-size: 17px; font-weight: 800; color: var(--p-ink);
              line-height: 1.25; margin-block-start: .2rem; }
.pub-fact-l { font-size: 12.5px; color: var(--p-muted); margin-block-start: .5rem; }

/* The course's sections, side by side. The wide one is נושאי לימוד. */
.pub-cols {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px; background: var(--p-line); border: 1px solid var(--p-line);
  margin-block-start: 3.4rem;
}
.pub-col { background: var(--p-paper); padding: 1.9rem 1.7rem; }
.pub-col-wide { grid-column: span 2; }
.pub-col h2 { font-size: 16px; font-weight: 800; letter-spacing: -.022em;
              margin: 0 0 .4rem; color: var(--p-brand-text, var(--p-brand)); }
.pub-col .pub-prose { margin-block-start: .6rem; max-inline-size: none; }
.pub-col .pub-prose h2 { margin-block-start: 1.2rem; }

/* A regulations page: contents beside the reading column. */
.pub-doc { display: grid; grid-template-columns: 250px minmax(0, 1fr);
           gap: 3.2rem; margin-block-start: 2.6rem; align-items: start; }
.pub-doc-plain { grid-template-columns: minmax(0, 1fr); }
.pub-toc { position: sticky; top: 1.5rem;
           border-inline-start: 2px solid var(--p-line); padding-inline-start: 1.1rem; }
.pub-toc-h { font-family: var(--p-mono); font-size: 10.5px; letter-spacing: .14em;
             color: var(--p-muted); margin-block-end: .9rem; }
/* ⚠ 24px MINIMUM, like every other link class here. These measured 20px in a
   real browser — a column of them, on the pages people arrive at looking for
   one clause. Flagged in review as minor and not fixed then; the sweep found
   it again on every regulations page at all three widths. */
.pub-toc a { display: flex; align-items: center; min-block-size: 24px;
             font-size: 13.5px; color: var(--p-ink-3);
             text-decoration: none; margin-block-end: .35rem; line-height: 1.5; }
.pub-toc a:hover, .pub-toc a:focus-visible { color: var(--p-brand-text, var(--p-brand));
                                             text-decoration: underline; }
.pub-measure { max-inline-size: 74ch; }
/* A fee table needs the full width, so it escapes the measure. It scrolls
   inside its own wrapper — the table stays intact, which is the opposite of
   cutting it. */
.pub-doc .pub-tablewrap { max-inline-size: none; }

/* An editorial page: one column, the page's own featured image beside it. */
.pub-art { display: grid; grid-template-columns: minmax(0, 1fr) 320px;
           gap: 3.6rem; align-items: start; }
.pub-art-fig img { inline-size: 100%; block-size: auto; display: block;
                   border: 1px solid var(--p-line); }
.pub-art .pub-sec-head { margin-block-end: 0; }

@media (max-width: 900px) {
  .pub-cols { grid-template-columns: minmax(0, 1fr); }
  .pub-col-wide { grid-column: auto; }
  .pub-doc, .pub-art { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  /* Contents above the document, not stuck to the side of it. */
  .pub-toc { position: static; }
  .pub-art-fig { order: -1; max-inline-size: 320px; }
}

/* ⚠ PRINT: NOTHING IS SPLIT ACROSS A PAGE BREAK. A regulations page is the one
   thing on this site somebody genuinely prints — a student takes תקנון שכר לימוד
   to a bank, a garage prints a course's admission criteria — and the same rule
   that forbids clipping a label on a phone forbids severing a card or a table
   row across two sheets. A heading is kept with what follows it so no section
   title is left alone at the foot of a page. */
@media print {
  .pub-fact, .pub-col, .pub-cell, .pub-fig, .pub-docs li,
  .pub-table tr, .pub-field, .pub-prose .pub-list li { break-inside: avoid; }
  .pub-sec-head, .pub-prose h2, .pub-prose h3, .pub-prose h4,
  .pub-prose h5, .pub-prose h6, .pub-col h2 { break-after: avoid; }
  /* The contents list is a way in, not part of the document. */
  .pub-toc { display: none; }
  .pub-doc { display: block; }
}

/* ── a branch card on a branches page ─────────────────────────────────────
   The card is a .pub-cell — it inherits the ring that draws the grid's
   hairlines — and adds a map, a name/address head and a rows list. The rows
   are a <dl>: label and value, which is what they are, so a screen reader
   reads "משרד, 03-5453205" rather than two loose links. */
.pub-branch { gap: 1rem; }
.pub-branch-head { display: flex; flex-direction: column; gap: .15rem; }
.pub-branch-where { font-size: 13px; color: var(--p-muted); }
/* The map sits on the same hairline as everything else and never grows past
   one glance — four of these are on the page at once.
   ⚠ THE SELECTOR CARRIES .pub-branch ON PURPOSE. `.pub-embed iframe` sets
   `aspect-ratio: 16/9` and is declared LATER in this file at the same
   specificity (0,1,1), so `.pub-branch-map iframe` lost and every map rendered
   at 16/9 — about 280px in a half-width card, four times down the page. Adding
   the parent makes it (0,2,1) and it wins wherever it sits. The aspect-ratio
   has to be unset too, or it fights the height it just lost to. */
.pub-branch-map { margin: 0; }
.pub-branch .pub-branch-map iframe { aspect-ratio: auto; block-size: 168px; }
/* margin-block-start:auto pins the rows to the foot, so two cards of unequal
   text still line their numbers up. */
.pub-branch-rows { margin: auto 0 0; display: flex; flex-direction: column; }
.pub-branch-row { display: flex; align-items: center; gap: .9rem;
  padding-block: .55rem; border-block-start: 1px solid var(--p-line); }
.pub-branch-row:last-child { border-block-end: 1px solid var(--p-line); }
.pub-branch-row dt { font-family: var(--p-mono); font-size: 10.5px;
  letter-spacing: .1em; color: var(--p-muted-2); inline-size: 74px;
  flex-shrink: 0; }
.pub-branch-row dd { margin: 0; display: flex; align-items: center; gap: .9rem;
  flex: 1 1 auto; font-size: 14.5px; font-weight: 600; }
.pub-branch-wa { margin-inline-start: auto; display: inline-flex;
  align-items: center; gap: .35rem; font-size: 12.5px; font-weight: 600;
  color: var(--p-muted); }
/* ⚠ ON A PHONE THE DIAL COMES FIRST. A garage's desk is an old Windows machine
   and the phone is the capable device, so below the two-column breakpoint the
   label column collapses and the value gets the full width — the number stays
   a 44px target instead of sharing a line with a 74px label. The map goes
   shorter rather than away: it is how somebody finds the branch. */
@media (max-width: 620px) {
  .pub-branch-row { align-items: flex-start; flex-direction: column; gap: .1rem; }
  .pub-branch-row dt { inline-size: auto; }
  .pub-branch-row dd { inline-size: 100%; min-block-size: 34px; }
  .pub-branch .pub-branch-map iframe { block-size: 132px; }
}

/* The enquiry beside its introduction. One column of prose, two of form —
   the form is capped at 62ch by .pub-enquiry, so a full-width row left half of
   itself empty. Collapses to one column with the rest of the page at 980px. */
.pub-branch-ask { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 3rem; align-items: start; }
.pub-branch-ask-form { grid-column: span 2; }
.pub-branch-ask-form .pub-enquiry { margin-block-start: 0; max-inline-size: none; }
.pub-branch-ask-say h2 { font-size: clamp(20px, 2.2vw, 26px); font-weight: 900;
  letter-spacing: -.03em; margin: 0 0 .8rem; line-height: 1.15; }
.pub-branch-ask-say p { font-size: 14.5px; color: var(--p-ink-3); margin: 0; }
@media (max-width: 980px) {
  .pub-branch-ask { grid-template-columns: 1fr; gap: 1.6rem; }
  .pub-branch-ask-form { grid-column: auto; }
}

/* A consent checkbox: the box first, its statement beside it, wrapping freely.
   The statement is what the person is agreeing to, so it is never clipped and
   never becomes a placeholder. */
.pub-field-check { display: flex; align-items: flex-start; gap: .55rem;
                   flex-direction: row-reverse; justify-content: flex-end; }
/* ⚠ inline-flex, NOT inline. `display: inline` was set here only to beat
   `.pub-field label { display: block }`, and it costs the target: min-block-size
   does not apply to a non-replaced inline box, so the consent label measured
   22px — the whole tap area for a box a person is agreeing to something with.
   inline-flex beats block just as well AND takes a minimum. */
.pub-field-check label { display: inline-flex; align-items: center;
                         min-block-size: 24px; order: 2; font-weight: 400;
                         font-size: 13.5px; line-height: 1.6; margin-block-end: 0; }
.pub-field-check input[type="checkbox"] { order: 1; margin-block-start: .2rem;
                                          inline-size: auto; flex: none; }

/* A checkbox GROUP: its legend is the question, each option is a choice.
   Options wrap onto as many lines as they need — a study-track name is never
   clipped to fit a column. */
.pub-fieldset { border: 1px solid var(--p-line); padding: .9rem 1rem 1rem;
                margin: 0; background: var(--p-paper); }
.pub-fieldset legend { font-size: 13.5px; font-weight: 600; padding-inline: .4rem; }
/* ⚠ SCOPED UNDER .pub-fieldset ON PURPOSE. `.pub-field label` sets
   display:block and outranks a bare `.pub-check`, so the flex row never
   applied: the gap collapsed and every box sat flush against its own text
   ("☐מסלול חד שנתי מואץ"). Specificity, not !important. */
/* min-block-size, like every other control: a choice in a group is pressed as
   often as any other link on the page, and these measured 22px. */
.pub-fieldset .pub-check { display: flex; align-items: flex-start; gap: .55rem;
             min-block-size: 24px; padding-block: .15rem;
             font-size: 13.5px; line-height: 1.6; font-weight: 400;
             margin-block-start: .45rem; margin-block-end: 0; }
.pub-fieldset .pub-check input { inline-size: auto; flex: none;
             margin-block-start: .25rem; margin-inline: 0; }
.pub-fieldset .pub-check span { min-inline-size: 0; }

/* A third-party embed — a campus map, a film. Sized by ratio so it fills its
   column at any width and never overflows on a phone; the frame carries no
   border of its own. */
.pub-embed { margin-block: 1.4rem; border: 1px solid var(--p-line);
             max-inline-size: 100%; }
.pub-embed iframe { display: block; inline-size: 100%; aspect-ratio: 16 / 9;
                    block-size: auto; border: 0; }

/* ── The front page's course cards ────────────────────────────────────────────
   ⚠ THE TITLE OVERLAYS THE IMAGE, WHICH IS WHAT THE ORIGINAL DOES AND ALSO WHY
   IT SURVIVES A MISSING PICTURE. With the image stacked ABOVE the title, the
   two courses that carry no featured image (neither has a _thumbnail_id in the
   export) rendered as two thirds white space beside cards that had one. As an
   overlay a card with no image is a solid brand panel with its name on it,
   which reads as deliberate.

   Two per row rather than three, also matching the original: at three across, a
   16:9 photograph is small enough that the workshop in it is unreadable. */
.pub-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
             gap: 1.2rem; }
/* ⚠ THE OVERLAY IS GONE, AND ITS REASON WENT FIRST. These cards used to be a
   picture with the title laid over it under a dark scrim — the right treatment
   when 24 of the 25 courses had no picture at all, because a card with nothing
   in it was then a solid brand-green panel rather than an obvious hole.
   Every card now carries artwork, and the artwork is LIGHT: flat vector on a
   warm off-white ground. White text over that needs a scrim of about .9 where
   the title sits, which turns an airy illustration into a muddy grey-green
   wash — measured in a browser on the deployed page, not argued. Stacked, the
   picture is a picture and the title is black on paper.

   The band is 16:9 rather than a fixed height so the illustrations, which are
   drawn 16:9, are never cropped. A photograph in the same grid is cropped to
   fit, which is what cover is for. */
.pub-card { position: relative; display: flex; flex-direction: column;
            overflow: hidden; min-block-size: 210px; background: var(--p-paper);
            border: 1px solid var(--p-line); text-decoration: none;
            border-radius: var(--p-radius); }
.pub-card img { inline-size: 100%; aspect-ratio: 16 / 9; object-fit: cover;
                display: block; background: var(--p-wash); }
.pub-card-body { display: flex; flex-direction: column; justify-content: flex-end;
                 flex: 1 1 auto; padding: 1.1rem 1.3rem 1.3rem; }
/* ⚠ A CARD WITH NO PICTURE IS A COMPACT CARD, NOT A 210px SLAB OF BRAND GREEN.
   24 of the 25 courses share WordPress's default placeholder, which is ignored
   at import (see build_brand_site.py) — so most cards have no image, and the
   overlay treatment turned each one into a large empty rectangle. The ORIGINAL
   has no course images either and does not look like this: its cards are
   compact, light, title-and-line. Same here, so an imageless card reads as a
   card rather than as a picture that failed to load. */
/* ⚠ THE SAME HEIGHT AS AN IMAGE CARD. Making the imageless ones compact fixed
   the empty-slab look and broke the grid instead: short cards beside tall ones,
   rows that do not line up, a page that reads as broken rather than as designed.
   A card without a picture is a WHITE card of the same size — the title has room
   and the row stays true. */
/* .pub-card-plain is now the same card without the picture band — the template
   still marks it, and the only thing left to say is that it keeps its height so
   the row stays true. */
.pub-card-plain { background: var(--p-paper); }
.pub-card-title { color: var(--p-ink); font-size: 17px; font-weight: 800;
                  letter-spacing: -.022em; line-height: 1.3; }
.pub-card-more { color: var(--p-brand-text, var(--p-brand)); font-size: 13px;
                 font-weight: 600; margin-block-start: .45rem; }
.pub-card:hover .pub-card-title, .pub-card:focus-visible .pub-card-title {
  text-decoration: underline; }
@media (max-width: 720px) {
  .pub-cards { grid-template-columns: minmax(0, 1fr); }
}

/* The header's own action link — the student login on the college's site.
   Quiet by design: it sits beside the language toggle, not in the nav. */
.pub-btn-quiet { border: 1px solid var(--p-line); background: none;
                 color: var(--p-ink-3); font-size: 13px; font-weight: 600;
                 padding: .38rem .8rem; text-decoration: none;
                 white-space: nowrap; }
.pub-btn-quiet:hover, .pub-btn-quiet:focus-visible {
  border-color: var(--p-brand-text, var(--p-brand)); color: var(--p-ink); }

/* Site search — the header box and the results page. */
.pub-navsearch input { inline-size: 150px; padding: .34rem .6rem; font: inherit;
  font-size: 13px; border: 1px solid var(--p-line); background: var(--p-paper);
  color: var(--p-ink); }
.pub-navsearch input:focus-visible { outline: 2px solid var(--p-brand);
  outline-offset: 1px; inline-size: 200px; }
.pub-search { display: flex; gap: .6rem; margin-block: 1.4rem 1.2rem;
              max-inline-size: 46rem; }
.pub-search input { flex: 1; min-inline-size: 0; padding: .55rem .8rem;
  font: inherit; font-size: 15px; border: 1px solid var(--p-line);
  background: var(--p-paper); }
.pub-search-count { color: var(--p-muted); font-size: 13.5px; margin-block: 0 1.4rem; }
.pub-results { list-style: none; margin: 0; padding: 0; max-inline-size: 74ch; }
.pub-results li { border-block-start: 1px solid var(--p-line); padding-block: 1rem; }
.pub-results a { font-size: 16px; font-weight: 800; letter-spacing: -.022em; }
.pub-results p { margin: .35rem 0 0; color: var(--p-ink-3); font-size: 14px;
                 line-height: 1.75; }
/* ⚠ THE SEARCH NARROWS ON A PHONE, IT DOES NOT DISAPPEAR. It was
   `display:none` below 900px, and nothing else anywhere links to /search — so
   the feature was not degraded on mobile, it was unreachable. On a site whose
   navigation is a three-level menu, search is how a phone visitor finds a
   course. */
@media (max-width: 900px) {
  .pub-navsearch input { inline-size: 108px; }
  .pub-navsearch input:focus-visible { inline-size: 150px; }
}


/* The navigation disclosure. Hidden until the script reveals it, and only ever
   visible at the width where .pub-nav is folded — so with JS off the nav is
   simply the desktop nav, never a dead button. */
.pub-navtoggle { display: none; font: inherit; font-size: 13px; font-weight: 600;
  padding: .38rem .8rem; border: 1px solid var(--p-line);
  background: var(--p-paper); color: var(--p-ink-3); cursor: pointer;
  white-space: nowrap; }
.pub-navtoggle[aria-expanded="true"] { border-color: var(--p-brand-text, var(--p-brand));
  color: var(--p-ink); }
/* ⚠ THE REVEAL MUST COME AFTER THE BASE RULE, AND IT DID NOT. This block first
   lived in the @media at line ~1146, 700 lines ABOVE `.pub-navtoggle { display:
   none }` — same specificity, earlier in the file, so `none` won every time and
   the button could never appear at any width. The nav was still unreachable on
   a phone; the fix shipped and changed nothing.
   Rami's phone found it in one screenshot. The test did not, because it asserted
   the reveal rule EXISTS inside the media block — which was true — and a rule
   that exists and a rule that wins are different facts. */
@media (max-width: 980px) {
  .pub-navtoggle { display: inline-flex; align-items: center; }
}
/* ⚠ THE HEADER ROW MUST WRAP. It is brand + nav + search + Moodle link + lang
   toggle, none of it shrinkable, and it had no wrap rule at all — at 320px the
   row simply overflowed. */
.pub-head { flex-wrap: wrap; row-gap: .5rem; position: relative; }
.pub-actions { flex-wrap: wrap; row-gap: .5rem; align-items: center; }

/* ⚠ A PROSE CALL TO ACTION IS A TAP TARGET. The sitewide 24px minimum covers
   .pub-nav/.pub-more/.pub-foot links but not the CTA anchors inside imported
   prose, which measured 20px tall in a real browser — under the floor, on the
   links a course page most wants pressed. */
.pub-prose-cta a, .pub-prose p > a, .pub-results a {
  display: inline-flex; align-items: center; min-block-size: 24px;
}

/* The AI-disclosure under a grid of generated course illustrations
   (templates/_pub_art_note.html). Quiet, because it is a provenance note and
   not a message — but not hidden, because that is the whole point of it. */
.pub-note { color: var(--p-muted); font-size: 12.5px; line-height: 1.6;
  margin-block: 1.4rem 0; max-inline-size: 74ch; }

/* ── THE COLLEGE FRONT PAGE, to the design ───────────────────────────────────
   Claude Design project 14f6dfc1-fd08-4d03-899c-a31ca9d4849d, "College Home".
   Its whole vocabulary is one idea: a grid whose SEPARATORS are the background
   showing through 1px gaps, on a hairline border. No radius, no shadow, no
   second accent. Everything below is that, at four different column counts.

   ⚠ THE GAP IS PAINTED, NOT DRAWN, so an uncovered track is a visible slab —
   the same defect .pub-cols hit and documented. Every grid here therefore has
   a column count that divides its content, or `auto-fit` so there are no
   uncovered tracks to show. */
.pub-figs { position: relative; z-index: 2; border-top: 1px solid var(--p-line-dark);
  background: var(--p-ink-2); }
.pub-figs-in { max-inline-size: 1200px; margin-inline: auto; padding-inline: 2rem;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 1px; background: var(--p-line-dark); }
/* ⚠ pub-figS-cell, NOT pub-fig. The counted-statistics band and _pub_prose's
   IMAGE figure are unrelated components that both wanted the name "fig", and
   for two weeks they shared it: this dark background and padding landed on
   every photograph in every academy page body. Nobody saw it because the image
   filled the panel edge to edge — it appeared the moment a height cap made the
   picture narrower than its container, as a dark slab beside it. A name
   collision between two components is invisible exactly until one of them
   changes size. */
.pub-figs-cell { background: var(--p-ink-2); padding: 1.2rem 1.4rem; }
.pub-figs-n { font-family: var(--p-mono); font-size: 30px; font-weight: 600;
  letter-spacing: -.03em; color: var(--p-paper); }
/* --p-onink, not --p-muted: this label sits on the dark band, where the
   design's #8b8d91 measures 5.04:1. On paper it is 3.16:1 and must not be used. */
.pub-figs-l { font-size: 13px; color: var(--p-onink, var(--p-faint)); }

.pub-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px; background: var(--p-line); border: 1px solid var(--p-line); }
.pub-tile { display: flex; flex-direction: column; background: var(--p-paper);
  color: var(--p-ink); text-decoration: none; }
.pub-tile:hover, .pub-tile:focus-visible { background: var(--p-wash); }
.pub-tile-art { display: block; aspect-ratio: 16 / 10; background: var(--p-wash);
  overflow: hidden; }
.pub-tile-art img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.pub-tile-body { display: flex; flex-direction: column; gap: .5rem; flex: 1;
  padding: 1.1rem 1.3rem 1.2rem; }
.pub-tile-n { font-family: var(--p-mono); font-size: 11px; letter-spacing: .12em;
  color: var(--p-muted-2, var(--p-muted)); }
.pub-tile-title { font-size: 18px; font-weight: 600; letter-spacing: -.02em;
  line-height: 1.3; text-wrap: pretty; }
.pub-tile-more { margin-block-start: auto; font-size: 14px; font-weight: 600;
  color: var(--p-brand-text); }
.pub-tiles-more { display: flex; justify-content: center; margin-block: 1.4rem 0; }

.pub-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 2.5rem; }
.pub-tracks { display: grid; gap: 1px; background: var(--p-line);
  border: 1px solid var(--p-line); }
.pub-track { display: flex; justify-content: space-between; align-items: center;
  gap: 1rem; background: var(--p-paper); color: var(--p-ink);
  padding: 1.3rem 1.5rem; text-decoration: none; }
.pub-track:hover, .pub-track:focus-visible { background: var(--p-wash); }
.pub-track-t { display: block; font-size: 19px; font-weight: 600; letter-spacing: -.02em; }
.pub-track-s { display: block; font-size: 13px; color: var(--p-muted-2, var(--p-muted)); }
.pub-track .pub-more { white-space: nowrap; }

/* ⚠ SEVEN, AS THE DESIGN AND THE ORIGINAL BOTH HAVE — AND THE HAIRLINES ARE ON
   THE CELLS, NOT PAINTED THROUGH THE GAPS.

   I replaced the design's fixed 7 with auto-fit and wrote a comment here
   claiming that was the safer choice because an uncovered track paints as a
   grey slab. auto-fit then chose NINE columns for fourteen logos, leaving four
   uncovered tracks in the second row, and painted exactly the grey slab the
   comment was about. Rami: "You ruined this — it was 7 on each row."

   The column count was never the fix. Painting separators as a background
   showing through 1px gaps is what makes an uncovered track visible, so the
   separators are now BORDERS on the cells: the container draws the top and end
   edges, each cell draws its own bottom and start edge, and a row with three
   cells in it simply ends after three. Any column count is safe now, which is
   why the breakpoints below can pick whatever reads best rather than whatever
   happens to divide fourteen. */
.pub-logogrid { display: grid; gap: 0;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border-block-start: 1px solid var(--p-line);
  border-inline-end: 1px solid var(--p-line); }
.pub-logogrid span { display: flex; align-items: center; justify-content: center;
  background: var(--p-paper); padding: 1rem; min-block-size: 84px;
  border-block-end: 1px solid var(--p-line);
  border-inline-start: 1px solid var(--p-line); }
.pub-logogrid img { max-inline-size: 100%; max-block-size: 48px;
  object-fit: contain; filter: grayscale(1); opacity: .75; }
.pub-logogrid span:hover img { filter: none; opacity: 1; }

@media (max-width: 900px) {
  .pub-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pub-logogrid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .pub-tiles { grid-template-columns: minmax(0, 1fr); }
  .pub-logogrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ⚠ SCOPED TO .pub-brand-hero. Written unscoped, it overrode the sitewide
   .pub-hero-cta rule 1000 lines above it and so restyled IGA's own hero on
   pub_home.html and pub_members.html — the same shape as the .pub-fig collision
   below, found by the same sweep: a rule written inside the college's design
   section without the selector that keeps it there. .pub-brand-hero is on the
   academies' hero only, so both of them keep the design and IGA keeps its. */
.pub-brand-hero .pub-hero-cta { display: flex; gap: .75rem; flex-wrap: wrap; margin: .8rem 0 0; }
/* The outlined second action. --p-btn-ghost is white here because it sits on
   the ink; on paper it would be the ink itself. */
.pub-btn-ghost { background: none; border: 1px solid currentColor; color: inherit; }
.pub-btn-ghost:hover, .pub-btn-ghost:focus-visible {
  background: var(--p-paper); color: var(--p-ink); border-color: var(--p-paper); }

/* ── THE FOOTER, to its design ───────────────────────────────────────────────
   Brand and nav across the top, the four campuses as one four-column band each
   headed by a rule, one legal row. The 2fr/1fr/1fr grid above stays for a brand
   with a single office.

   ⚠ EVERY COLOUR HERE WAS WRITTEN FOR A DARK BAND, AND THE BAND WENT LIGHT ON
   15.9.2026. .pub-foot took the college's tint (#eff4f6) and the tokens two
   hundred lines up were moved with it — but this sibling block, added later,
   was not, and six of its rules kept dark-surface tokens on a near-white
   ground: the brand name and all four campus headings at --p-paper (1.11:1),
   the sub-tags and the blurb at --p-onink/--p-faint (1.93:1), and every mailto
   at --p-brand-bright, which the .pub block states flatly is never text on
   light (1.75:1 here). Not a contrast-checker quibble — invisible to a sighted
   reader, on a footer that is on every page of the college's live site.

   The sweep that found it is the lesson: a surface that flips takes EVERY rule
   painting on it, and the two footers are siblings 200 lines apart in one file,
   which is exactly the distance at which "grep for the sibling" stops being
   optional. tests/test_a11y.py could not see it — its --p-faint check names two
   selectors by hand rather than sweeping the stylesheet, and --p-paper is never
   tested as a text colour at all. test_no_dark_surface_token_carries_text_on_a
   _light_one now sweeps for the shape. */
.pub-foot-top { max-inline-size: 1240px; margin-inline: auto;
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: .9rem 3rem; align-items: start;
  /* --p-line-2, not --p-line-dark: the latter is the hairline ON THE DARK
     BANDS and draws a near-navy bar across a near-white footer. */
  padding-block-end: 2.2rem; border-block-end: 1px solid var(--p-line-2); }
.pub-foot-brand { display: flex; align-items: center; gap: .9rem; }
.pub-foot-mark { inline-size: 44px; block-size: 44px; object-fit: contain; display: block; }
.pub-foot-name { margin: 0; font-size: 17px; font-weight: 700;
  letter-spacing: -.02em; color: var(--p-ink); }
.pub-foot-sub { display: block; font-family: var(--p-mono); font-size: 11px;
  letter-spacing: .14em; color: var(--p-muted); }
.pub-foot-blurb { grid-column: 1; margin: 0; font-size: 14px; line-height: 1.7;
  max-inline-size: 44ch; color: var(--p-ink-3); }
/* ⚠ gap, NOT SOURCE WHITESPACE. .pub-foot a is display:block, so as inline
   siblings these ran together into one unspaced line. */
.pub-foot-nav { grid-column: 2; grid-row: 1 / span 2;
  display: flex; flex-wrap: wrap; gap: .2rem 1.75rem;
  align-items: center; justify-content: flex-end; max-inline-size: 54ch; }
.pub-foot-nav a { font-size: 14px; }

.pub-foot-branches { max-inline-size: 1240px; margin-inline: auto;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 2rem; padding-block: 2.2rem 2.4rem; }
.pub-foot-branch { display: flex; flex-direction: column;
  border-block-start: 2px solid var(--p-brand-bright); padding-block-start: 1rem; }
.pub-foot-tag { font-family: var(--p-mono); font-size: 11px; letter-spacing: .14em;
  color: var(--p-muted); }
.pub-foot-h2 { margin: .1rem 0 .55rem; font-size: 17px; font-weight: 600;
  letter-spacing: -.02em; color: var(--p-ink); }
.pub-foot-branch a, .pub-foot-branch span { font-size: 14px; padding-block: .18rem; }
.pub-foot-branch > a:first-of-type { color: var(--p-ink); }
.pub-foot-mail { color: var(--p-brand-text); text-decoration: underline; }
.pub-foot-mail:hover { color: var(--p-ink); }

@media (max-width: 1000px) {
  .pub-foot-branches { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pub-foot-top { grid-template-columns: minmax(0, 1fr); }
  .pub-foot-nav { grid-column: 1; grid-row: auto; justify-content: flex-start; }
}
@media (max-width: 560px) {
  .pub-foot-branches { grid-template-columns: minmax(0, 1fr); }
}

/* =============================================
   THE WALLET — /store

   The balance used to be a `.card.stat` inside a `.grid-2` beside the top-up
   card. Grid children are equal height, the two panels held wildly unequal
   content, and the result was a single number floating at the top of a box of
   nothing. This band is the fix: the figure and the control that moves it are
   ONE bordered surface split in two, so neither can strand the other.

   Everything here is the site's existing vocabulary — navy, square, 1px
   hairlines, Heebo and JetBrains Mono. No new colour is introduced.
   ============================================= */

.wallet-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 2rem; flex-wrap: wrap; margin-block-end: 1.4rem;
}
.wallet-head h1 { margin-block-end: 0; }
.wallet-lede { margin-block-start: .5rem; max-inline-size: 58ch; }
.wallet-who {
  font-size: .72rem; letter-spacing: .1em; color: var(--text-faint);
  padding-block-end: .5rem;
  /* No nowrap: a long garage name has to be allowed to wrap rather than run
     out of its box. NEVER CUT CONTENT IN THE MIDDLE. */
  max-inline-size: 30ch; text-align: end;
}
/* The monospace FACE without the direction flip: for a run that is Hebrew
   prose carrying digits, where .mono's direction:ltr would reorder the words. */
.mono-inline {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
}

.wallet {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  border: 1px solid var(--border); background: var(--card);
  margin-block-end: 1rem;
}

/* ---- the balance half ---- */
.wallet-balance {
  display: flex; flex-direction: column; gap: 1.15rem;
  /* The balance half always has less to say than the top-up half, and grid
     children are equal height — so the surplus has to GO somewhere. Pinning the
     meta rail to the bottom pooled all of it into one hole under the bar.
     Centring the figure group splits it above and below instead, which reads as
     composition rather than as a panel that ran out of content. */
  padding: 1.7rem 1.7rem 1.5rem;
  background: var(--primary-tint);
  /* LOGICAL, so the rule between the halves sits on the correct edge under
     dir=rtl without a second declaration. */
  border-inline-start: 1px solid var(--border);
}
.wallet-balance.is-low, .wallet-balance.is-empty { background: var(--red-light); }

.wallet-group { margin-block: auto; display: flex; flex-direction: column; gap: 1.15rem; }
.wallet-label { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; }
.wallet-kicker {
  font-size: .7rem; letter-spacing: .14em; color: var(--text-muted); font-weight: 600;
}
.wallet-chip {
  display: inline-flex; align-items: center; gap: .3rem;
  font-size: .72rem; font-weight: 600;
  padding-block: .16rem; padding-inline: .5rem;
  color: var(--emerald); background: var(--emerald-light);
  border: 1px solid var(--emerald);
}
.wallet-dot { inline-size: .4rem; block-size: .4rem; background: currentColor; }
.is-low .wallet-chip, .is-empty .wallet-chip {
  color: var(--red); background: var(--red-light); border-color: var(--red);
}

.wallet-figure {
  font-family: var(--font-mono); font-size: clamp(2.4rem, 5vw, 3.4rem);
  font-weight: 600; letter-spacing: -0.045em; line-height: 1;
  color: var(--text); unicode-bidi: isolate; text-align: start;
}
.is-low .wallet-figure, .is-empty .wallet-figure { color: var(--red); }

/* The bar compares the money to the association's threshold and to nothing
   else. It deliberately does not imply a number of certificates. */
.wallet-bar { block-size: 4px; background: var(--border-hairline); position: relative; }
.wallet-bar-fill { block-size: 4px; background: var(--emerald); }
.is-low .wallet-bar-fill, .is-empty .wallet-bar-fill { background: var(--red); }
.wallet-bar-mark {
  position: absolute; inset-block-start: -3px;
  inline-size: 1px; block-size: 10px; background: var(--text-muted);
}
.wallet-bar-legend {
  display: flex; justify-content: space-between; gap: 1rem;
  color: var(--text-faint); margin-block-start: -.7rem;
}

/* A definition list, because these ARE term/value pairs — and the panel's
   bottom rail, so the balance half fills its height with facts instead of the
   void that sat between the bar and a single line. */
.wallet-foot {
  margin-block-end: 0; padding-block-start: 1rem;
  border-block-start: 1px solid var(--border-hairline);
  display: grid; gap: .55rem; color: var(--text-muted);
}
.wallet-foot > div {
  display: flex; justify-content: space-between; gap: 1rem; align-items: baseline;
}
.wallet-foot dt { margin: 0; }
.wallet-foot dd { margin: 0; color: var(--text-secondary); }

/* ---- the top-up half ---- */
.wallet-topup { padding: 1.7rem 1.7rem 1.5rem; display: flex; flex-direction: column; }
.wallet-topup h2 { margin-block-end: .35rem; }
.wallet-form { display: flex; flex-direction: column; gap: .95rem; flex: 1; margin-block-start: .95rem; }
.wallet-form .notice { margin-block: 0; }
.wallet-cta { margin-block-start: auto; display: flex; flex-direction: column; gap: .7rem; }
.wallet-pay { inline-size: 100%; }

/* ---- the amounts: a radio group that reads as a row of choices ---- */
.amount-set { border: 0; padding: 0; margin: 0; min-inline-size: 0; }
.amount-legend {
  padding: 0; font-size: .82rem; font-weight: 600;
  color: var(--text-secondary); margin-block-end: .45rem;
}
.amount-row { display: flex; flex-wrap: wrap; gap: .5rem; }
.amount {
  display: inline-flex; align-items: center; justify-content: center;
  min-block-size: 2.9rem; padding-block: .6rem; padding-inline: .95rem;
  /* WCAG 1.4.11 wants 3:1 for the boundary of a meaningful component, and
     --border-strong (#ced0cf) is 1.55:1 on white — an unselected pill had no
     visible edge for a low-vision user. --text-muted measures 5.65:1 and stays
     lighter than the selected state. Measured, not eyeballed. */
  border: 1px solid var(--text-muted); background: var(--card);
  color: var(--text-secondary); font-size: .9rem; cursor: pointer;
}
/* The input stays in the accessibility tree — it is the control. Only its
   painting is replaced, so arrow keys, the group's name and a screen reader's
   "radio, 2 of 5" all still work. */
.amount input { position: absolute; opacity: 0; pointer-events: none; }
.amount:hover { border-color: var(--primary-edge); }
.amount:has(input:checked) {
  background: var(--primary); border-color: var(--primary);
  color: #fff; font-weight: 600;
}
.amount:has(input:focus-visible) { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ---- auto top-up ---- */
.autotopup-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 1.2rem 2rem; align-items: start;
}
/* One flex row, so the box and its words share a baseline. They used to be a
   block label wrapping a block input, which dropped the text onto its own line
   and left the box hanging above it. */
.autotopup-switch { display: flex; align-items: center; gap: .6rem; cursor: pointer; }
.autotopup-switch input {
  inline-size: 1.05rem; block-size: 1.05rem; accent-color: var(--primary);
  margin: 0; cursor: pointer; flex: 0 0 auto;
}
.autotopup-title { font-size: 1.15rem; font-weight: 800; letter-spacing: -0.025em; }
.autotopup-help { margin-block-start: .5rem; max-inline-size: 62ch; line-height: 1.6; }
.autotopup-controls { display: flex; align-items: flex-end; gap: .75rem; flex-wrap: wrap; }
.autotopup-controls .field { margin-block-end: 0; }
.autotopup-controls select { min-inline-size: 8rem; }
.autotopup-save { min-block-size: 2.9rem; }

/* ---- the ledger ---- */
.ledger { padding: 0; }
.ledger-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; padding: 1.4rem 1.7rem .9rem;
}
.ledger-head h2 { margin-block-end: 0; }
.ledger-tbl .num-col { text-align: end; }
.ledger-amount { font-weight: 600; }
.ledger-amount.is-in { color: var(--emerald); }
.ledger-amount.is-out { color: var(--text-secondary); }

@media (max-width: 860px) {
  .wallet { grid-template-columns: minmax(0, 1fr); }
  /* An even grid rather than a wrapping flex row: five buttons of different
     label widths wrapped into a ragged second line. */
  .amount-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .amount { padding-inline: .5rem; }
  .wallet-balance { border-inline-start: 0; border-block-end: 1px solid var(--border); }
  .autotopup-grid { grid-template-columns: minmax(0, 1fr); }
  .autotopup-controls { align-items: stretch; }
}

/* =============================================
   כנסים ואירועים — /events, the event page, the ticket and the home banner.
   The ticket follows the Claude Design canvas "IGA Conference Wallet Pass"
   (24.9.2026): navy card, the association's logo on the Save the Date car,
   one big QR. Everything else wears the public site's own tokens.
   ============================================= */
.ev-lead { max-inline-size: 72ch; color: var(--p-ink-3); font-size: 15px; margin-block-end: 1.6rem; }
.ev-h2 { font-size: 22px; margin-block: 2.2rem 1rem; }
.ev-empty { color: var(--p-muted); padding-block: 1rem; }
.ev-hint { color: var(--p-muted); font-size: 13.5px; }
.ev-drafts { background: var(--p-wash); border: 1px dashed var(--p-line-2); padding: 1rem 1.2rem; border-radius: var(--p-radius-btn); }
.ev-drafts ul { margin: .4rem 0 0; padding-inline-start: 1.2rem; }

.ev-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); gap: 1.4rem; }
.ev-card { background: var(--p-paper); border: 1px solid var(--p-line); border-radius: var(--p-radius); overflow: hidden; display: flex; flex-direction: column; break-inside: avoid; }
.ev-card-img { position: relative; display: block; aspect-ratio: 1032 / 336; background: var(--p-ink-2); }
.ev-card-img img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.ev-date { position: absolute; inset-block-end: .7rem; inset-inline-start: .7rem; background: var(--p-paper); color: var(--p-ink); font-weight: 700; padding: .25rem .6rem; border-radius: var(--p-radius-btn); font-size: 14px; }
.ev-card-body { padding: 1.1rem 1.2rem 1.2rem; display: flex; flex-direction: column; gap: .35rem; flex: 1; }
.ev-card-body h3 { font-size: 19px; margin: 0; line-height: 1.3; }
.ev-card-body h3 a { color: var(--p-ink); }
.ev-sub, .ev-where { margin: 0; color: var(--p-ink-3); font-size: 14.5px; }
.ev-card-foot { margin-block-start: auto; padding-block-start: .6rem; display: flex; flex-wrap: wrap; justify-content: space-between; gap: .5rem; font-size: 14px; }
.ev-state { font-weight: 600; }
.ev-state-open { color: #0a7c4c; }
.ev-price { color: var(--p-ink); font-weight: 600; }
.ev-grid-past .ev-card { opacity: .92; }

.ev-preview { background: #fff4d6; border-block-end: 1px solid #b57200; color: #5a3a00; padding: .7rem 2rem; margin: 0; font-weight: 600; }
.ev-hero { position: relative; background: var(--p-ink); color: var(--p-paper); overflow: hidden; }
.ev-hero-grid { max-inline-size: 1240px; margin-inline: auto; padding: 2.6rem 2rem; display: grid; grid-template-columns: minmax(0, 1fr); gap: 2rem; align-items: center; }
.ev-hero-grid.has-media { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
.ev-hero-media { margin: 0; }
.ev-hero-media img { display: block; inline-size: 100%; max-block-size: 460px; object-fit: contain; border-radius: 14px; }
/* A scrim under the text, because the photo is whatever the admin uploaded:
   without it a light image puts white type under 4.5:1. */
.ev-hero-in { display: flex; flex-direction: column; gap: .6rem; min-inline-size: 0; }
.ev-hero h1 { color: var(--p-paper); font-size: clamp(28px, 4.2vw, 46px); line-height: 1.15; margin: 0; }
.ev-hero-sub { color: #8ed1fc; font-size: 18px; margin: 0; }
.ev-crumbs a { color: var(--p-faint); font-size: 14px; }
.ev-hero .ev-crumbs a { color: var(--p-faint); }
.ev-facts { display: flex; flex-wrap: wrap; gap: .6rem 2.2rem; margin: .8rem 0 0; }
.ev-facts dt { color: var(--p-faint); font-size: 13px; }
.ev-facts dd { margin: 0; font-weight: 700; font-size: 17px; }
.ev-cta { align-self: flex-start; margin-block-start: .8rem; }
.ev-hero .pub-btn-solid { background: var(--p-paper); border-color: var(--p-paper); color: var(--p-ink); }

.ev-layout { max-inline-size: 1240px; margin-inline: auto; padding: 2.6rem 2rem 4rem; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 420px); gap: 2.6rem; align-items: start; }
.ev-summary { font-size: 18px; color: var(--p-ink); font-weight: 500; }
.ev-body p, .ev-body li { font-size: 16px; line-height: 1.75; color: var(--p-ink-3); }
.ev-body h2 { font-size: 21px; margin-block: 1.6rem .5rem; }
.ev-body ul { padding-inline-start: 1.3rem; }
.ev-materials, .ev-policy { margin-block-start: 2.4rem; }
.ev-mat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: 1rem; }
.ev-video { background: #000; }
.ev-video iframe { inline-size: 100%; aspect-ratio: 16 / 9; border: 0; display: block; }

.ev-side { background: var(--p-paper); border: 1px solid var(--p-line); border-radius: var(--p-radius); padding: 1.4rem; position: sticky; inset-block-start: 1rem; }
.ev-side h2 { font-size: 22px; margin-block: 0 1rem; }
.ev-tickets { list-style: none; margin: 0 0 1.2rem; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.ev-ticket { border: 1px solid var(--p-line); border-radius: var(--p-radius-btn); padding: .8rem 1rem; break-inside: avoid; }
.ev-ticket-top { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.ev-ticket p { margin: .3rem 0 0; font-size: 14px; color: var(--p-ink-3); }
.ev-ticket-state { color: var(--p-muted) !important; }
.ev-ticket-on_sale .ev-ticket-state { color: #0a7c4c !important; font-weight: 600; }

.ev-form { display: flex; flex-direction: column; gap: 1rem; }
.ev-form fieldset { border: 0; border-block-start: 1px solid var(--p-line); padding: .9rem 0 0; margin: 0; display: flex; flex-direction: column; gap: .7rem; }
.ev-form legend { font-weight: 700; font-size: 16px; padding: 0; margin-block-end: .3rem; }
.ev-field { display: flex; flex-direction: column; gap: .3rem; font-size: 14.5px; font-weight: 500; }
.ev-field input, .ev-field select, .ev-field textarea { font: inherit; font-weight: 400; padding: .65rem .75rem; border: 1px solid var(--p-line-2); border-radius: var(--p-radius-btn); background: var(--p-paper); color: var(--p-ink); min-block-size: 44px; box-sizing: border-box; inline-size: 100%; }
.ev-field input:focus-visible, .ev-field select:focus-visible, .ev-field textarea:focus-visible { outline: 2px solid var(--p-ink); outline-offset: 1px; }
.ev-radio, .ev-check { display: flex; gap: .6rem; align-items: flex-start; font-size: 14.5px; line-height: 1.5; min-block-size: 32px; }
.ev-radio input, .ev-check input { margin-block-start: .3rem; inline-size: 18px; block-size: 18px; flex-shrink: 0; }
.ev-req { color: #a82820; }
.ev-req-note { font-size: 13px; color: var(--p-muted); margin: 0; }
.ev-hp { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); }
.ev-submit { inline-size: 100%; justify-content: center; min-block-size: 48px; font-size: 16px; }
.ev-error { background: #fdeceb; border: 1px solid #a82820; color: #6e1a15; padding: .8rem 1rem; border-radius: var(--p-radius-btn); margin-block-end: 1rem; }
.ev-ok { background: #e6f4ec; border: 1px solid #0e9e62; color: #064e30; padding: .9rem 1.1rem; border-radius: var(--p-radius-btn); margin-block-end: 1.2rem; }
.ev-ok p, .ev-error p { margin: .3rem 0 0; }
.ev-demo-note { background: #fff4d6; border: 1px solid #b57200; color: #5a3a00; padding: .7rem 1rem; border-radius: var(--p-radius-btn); font-size: 14px; }

.ev-narrow { max-inline-size: 640px; }
.ev-order-h { font-size: 28px; margin-block: .4rem .2rem; }
.ev-summary-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr)); gap: .8rem 1.4rem; margin-block: 1.4rem; }
.ev-summary-list dt { font-size: 13px; color: var(--p-muted); }
.ev-summary-list dd { margin: 0; font-weight: 600; }
.ev-att-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .6rem; }
.ev-att-list li { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1rem; border: 1px solid var(--p-line); border-radius: var(--p-radius-btn); padding: .6rem .9rem; }
.ev-att-list li .pub-btn { margin-inline-start: auto; }

/* The ticket — the design canvas's registration card, in the site's tokens. */
.ev-pass { background: var(--p-paper); border: 1px solid var(--p-line); border-radius: var(--p-radius); overflow: hidden; break-inside: avoid; }
.ev-pass-void { opacity: .6; }
.ev-pass-hero { position: relative; aspect-ratio: 1032 / 336; background: #050b1f; }
.ev-pass-hero > img:first-child { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.ev-pass-logo { position: absolute; inset-block-start: 10px; inset-inline-start: 10px; inline-size: 56px; block-size: 56px; border-radius: 50%; background: var(--p-paper); border: 2px solid var(--p-paper); }
.ev-pass-head { padding: 1rem 1.2rem; border-block-end: 1px dashed var(--p-line-2); }
.ev-pass-kicker { font-size: 13px; color: var(--p-muted); font-weight: 600; }
.ev-pass-head h1 { font-size: 24px; margin: .2rem 0; line-height: 1.25; }
.ev-pass-head p { margin: 0; color: var(--p-ink-3); }
.ev-pass-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .8rem 1rem; padding: 1rem 1.2rem; margin: 0; }
.ev-pass-fields dt { font-size: 12.5px; color: var(--p-muted); }
.ev-pass-fields dd { margin: 0; font-weight: 700; }
.ev-pass-qr { display: flex; flex-direction: column; align-items: center; padding: .4rem 1.2rem 1.4rem; }
.ev-qr svg { inline-size: 200px; block-size: 200px; display: block; }
/* The ticket page as the Wallet card (design canvas, Main artboard). */
.ev-wcard { background: #0b3059; color: #fff; border-radius: 20px; overflow: hidden; display: flex; flex-direction: column; break-inside: avoid; max-inline-size: 420px; margin-inline: auto; }
.ev-wcard-head { display: flex; align-items: center; gap: .7rem; padding: 1.1rem 1.25rem .4rem; font-size: 15px; font-weight: 500; }
.ev-wcard-logo { inline-size: 44px; block-size: 44px; border-radius: 50%; background: #fff; flex-shrink: 0; }
.ev-wcard-title { padding: .6rem 1.25rem .2rem; }
.ev-wcard-title h1 { color: #fff; font-size: 26px; font-weight: 800; line-height: 1.2; margin: 0; }
.ev-wcard-title p { color: #8ed1fc; font-size: 15px; margin: .25rem 0 0; }
.ev-wcard-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem .8rem; padding: 1rem 1.25rem; margin: 0; }
.ev-wcard-fields dt { font-size: 12px; color: #a9c3dc; }
.ev-wcard-fields dd { margin: .15rem 0 0; font-size: 16px; font-weight: 700; }
.ev-mono { font-family: var(--p-mono); font-weight: 600; }
.ev-wcard-qr { display: flex; flex-direction: column; align-items: center; gap: .5rem; padding: .4rem 1.25rem 1.3rem; }
.ev-wcard-qr .ev-mono { color: #a9c3dc; font-size: 13px; }
.ev-wcard-qrbox { background: #fff; padding: 12px; border-radius: 12px; }
.ev-wcard-qrbox svg { inline-size: 184px; block-size: 184px; display: block; }
.ev-wcard-void { background: #fdeceb; color: #6e1a15; padding: .6rem 1rem; border-radius: 8px; margin: 0; }
.ev-wcard-hero { inline-size: 100%; aspect-ratio: 1032 / 336; object-fit: cover; display: block; }
.ev-wcard-hint { text-align: center; }
.ev-inv-text { padding: 0 1.2rem 1.2rem; color: var(--p-ink-3); }
.ev-pass-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: .6rem; margin-block: 1.2rem; }
.ev-gwallet { display: inline-flex; align-items: center; justify-content: center; background: #1f1f1f; color: #fff; border-radius: 999px; padding: .7rem 1.4rem; min-block-size: 48px; font-weight: 500; }
.ev-gwallet:hover { background: #000; color: #fff; text-decoration: none; }
.ev-checkin { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-block: 1rem; }
.ev-rsvp { margin-block: 1.4rem; }
.ev-rsvp-btns { display: flex; flex-wrap: wrap; gap: .6rem; }

.ev-garage { position: relative; display: flex; flex-direction: column; gap: .7rem; }
.ev-garage-list { list-style: none; margin: -.4rem 0 0; padding: 0; border: 1px solid var(--p-line-2); border-radius: var(--p-radius-btn); background: var(--p-paper); max-block-size: 18rem; overflow-y: auto; }
.ev-garage-opt { display: flex; flex-direction: column; align-items: flex-start; gap: .1rem; inline-size: 100%; min-block-size: 44px; padding: .45rem .75rem; border: 0; border-block-end: 1px solid var(--p-line); background: none; font: inherit; text-align: start; cursor: pointer; color: var(--p-ink); }
.ev-garage-opt:hover, .ev-garage-opt:focus-visible { background: var(--p-wash); outline: 2px solid var(--p-ink); outline-offset: -2px; }
.ev-garage-meta { font-size: 13px; color: var(--p-muted); }
.ev-tbl-wrap { overflow-x: auto; margin-block: .6rem 1.2rem; }
.ev-tbl { border-collapse: collapse; inline-size: 100%; font-size: 14.5px; }
.ev-tbl th, .ev-tbl td { text-align: start; padding: .55rem .7rem; border-block-end: 1px solid var(--p-line); vertical-align: top; }
.ev-tbl thead th { color: var(--p-muted); font-weight: 600; font-size: 13px; }
.ev-tbl input { inline-size: 100%; min-inline-size: 220px; font: inherit; font-size: 13px; padding: .3rem .4rem; border: 1px solid var(--p-line-2); border-radius: 4px; }
.ev-tbl tr { break-inside: avoid; }
.ev-embedded .ev-hero-grid, .ev-embedded .ev-layout { padding-inline: 1rem; }

@media (max-width: 900px) {
  .ev-layout { grid-template-columns: minmax(0, 1fr); padding-inline: 1rem; }
  .ev-side { position: static; }
  .ev-hero-grid, .ev-hero-grid.has-media { grid-template-columns: minmax(0, 1fr); padding-inline: 1rem; gap: 1.4rem; }
  .ev-preview { padding-inline: 1rem; }
}
@media print {
  .ev-pass-actions, .ev-checkin, .pub-head, .pub-foot { display: none; }
}

/* ── The association's chat (templates/_iga_chat.html) ───────────────────────
   Ronen, 27.9.2026. A fixed panel at the inline-end corner; below 520px it
   takes the full width so no form field is ever narrower than its label. Text
   wraps, the body scrolls — nothing is clipped. */
.iga-chat-launch { position: fixed; inset-block-end: 1rem; inset-inline-end: 1rem; z-index: 60;
  background: var(--p-brand-text); color: var(--p-paper); border: 1px solid var(--p-brand-text);
  padding: .65rem 1.1rem; font-weight: 600; text-decoration: none; }
.iga-chat-launch:hover { background: var(--p-ink); border-color: var(--p-ink); color: var(--p-paper); text-decoration: none; }
.iga-chat-launch[hidden], .iga-chat[hidden], .iga-chat [hidden] { display: none; }
/* Design A (Rami, 28.9.2026). The panel stands --lift above the floor on a
   single-post in-ground car lift: a yellow saddle under it, a steel post, a pad
   in the floor (.iga-chat-lift, drawn BELOW the panel's own box). Opening from
   script it rises out of the bottom edge; the edge is the pit, so the post seems
   to come up out of the floor. Opened by the server (?chat=…) it is simply there
   — the rise is a class iga-chat.js adds, never the default. */
.iga-chat { --lift: 3.4rem; position: fixed; inset-block-end: var(--lift); inset-inline-end: 1rem; z-index: 61;
  inline-size: min(26rem, calc(100vw - 2rem)); max-block-size: calc(100vh - var(--lift) - 1rem);
  display: flex; flex-direction: column; background: var(--p-paper); color: var(--p-ink);
  border: 1px solid var(--p-line-2); box-shadow: 0 8px 30px rgb(0 0 0 / .18);
  transition: transform .7s cubic-bezier(.3, .7, .2, 1); }
.iga-chat.is-lowered { transform: translateY(calc(100% + var(--lift) + 2rem)); }
.iga-chat-head { display: flex; align-items: flex-start; justify-content: space-between; gap: .5rem;
  padding: .75rem 1rem .8rem; background: var(--p-ink); color: var(--p-paper); }
/* The label in Heebo, the figures in mono: a monospace face draws Hebrew at
   Latin cell width, so "כרטיס שירות" in it read as spaced-out letters
   (Rami, 28.9.2026). */
.iga-chat-ticket { margin: .15rem 0 0; font-size: 12px; color: var(--p-faint); }
.iga-chat-ticket-no { font-family: var(--p-mono); font-size: 11.5px; }
/* The tear line: a perforation with a notch cut out of each edge. */
.iga-chat-tear { position: relative; flex: none; block-size: 14px; }
.iga-chat-tear::before { content: ""; position: absolute; inset-block-start: 6px; inset-inline: 14px;
  block-size: 1px; background: repeating-linear-gradient(to left, var(--p-line-2) 0 5px, transparent 5px 10px); }
.iga-chat-tear::after { content: ""; position: absolute; inset-block-start: 0; inset-inline: -8px;
  block-size: 14px; background:
    radial-gradient(circle at 7px 7px, var(--p-wash) 6px, var(--p-line-2) 6.5px, transparent 7.5px) left / 14px 14px no-repeat,
    radial-gradient(circle at 7px 7px, var(--p-wash) 6px, var(--p-line-2) 6.5px, transparent 7.5px) right / 14px 14px no-repeat; }
.iga-chat-lift { position: absolute; inset-block-start: 100%; inset-inline: 0; block-size: calc(var(--lift) + 1px);
  display: flex; flex-direction: column; align-items: center; pointer-events: none; }
.iga-chat-saddle { inline-size: 40%; block-size: 7px; background: #d9a400; border: 1px solid #a87f00; box-sizing: border-box; }
.iga-chat-post { flex: 1; inline-size: 26px; background: #b9c3cd; border-inline: 1px solid #8e9aa6;
  box-shadow: inset -7px 0 0 -4px #e4e9ee; }
.iga-chat-pad { inline-size: 110px; block-size: 7px; background: #dce2e8; border: 1px solid var(--p-line-2);
  border-block-end: 0; box-sizing: border-box; }
.iga-chat-head h2 { margin: 0; font-size: 1.05rem; color: inherit; }
.iga-chat-close { color: inherit; font-size: 1.5rem; line-height: 1; text-decoration: none;
  min-inline-size: 44px; min-block-size: 44px; display: inline-flex; align-items: center; justify-content: center; }
.iga-chat-close:hover { color: inherit; text-decoration: none; }
.iga-chat-body { overflow-y: auto; padding: 1rem; font-size: 14.5px; line-height: 1.7; }
.iga-chat-body h3 { margin: .2rem 0 .6rem; font-size: 1.05rem; }
.iga-chat-body h4 { margin: 1rem 0 .4rem; font-size: 1rem; }
.iga-chat-topics { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem;
  grid-template-columns: repeat(2, minmax(0, 1fr)); }
.iga-chat-topics a { display: flex; flex-direction: column; justify-content: space-between; gap: .5rem;
  block-size: 100%; box-sizing: border-box; min-block-size: 4.9rem; padding: .75rem;
  border: 1px solid var(--p-line); color: var(--p-ink); text-decoration: none;
  font-size: 14px; font-weight: 500; line-height: 1.3; }
.iga-chat-topics svg { color: var(--p-ink-3); }
.iga-chat-topics a:hover, .iga-chat-topics a:focus-visible { border-color: var(--p-brand-text); color: var(--p-brand-text); }
.iga-chat-topics a:hover svg, .iga-chat-topics a:focus-visible svg { color: var(--p-brand-text); }
.iga-chat-back { font-size: 13.5px; }
.iga-chat-sub { margin: .6rem 0 .2rem; font-size: 13px; font-weight: 600; color: var(--p-ink-3); }
.iga-chat-li { margin: 0 0 .3rem; padding-inline-start: .6rem; }
.iga-chat-note { font-size: 13px; color: var(--p-ink-3); }
.iga-chat form .pub-field { margin-block: .7rem; }
.iga-chat form .pub-fieldset { margin: 0 0 .6rem; }
/* The free-text box and its conversation. */
.iga-chat-ask { margin-block-start: 1rem; border-block-start: 1px solid var(--p-line); padding-block-start: .8rem; }
.iga-chat-log { display: flex; flex-direction: column; gap: .5rem; }
.iga-chat-log:not(:empty) { margin-block-end: .8rem; }
.iga-chat-msg { max-inline-size: 88%; padding: .55rem .75rem; line-height: 1.6; white-space: pre-line;
  overflow-wrap: anywhere; background: var(--p-wash); border: 1px solid var(--p-line); align-self: flex-start; }
.iga-chat-msg.is-user { align-self: flex-end; background: var(--p-ink); border-color: var(--p-ink); color: var(--p-paper); }
.iga-chat-checking { display: flex; align-items: center; gap: .5rem; font-size: 13px; color: var(--p-muted); }
.iga-chat-gauge { color: var(--p-muted); flex: none; }
.iga-chat-gauge circle { fill: var(--p-ink); }
.iga-chat-needle { stroke: var(--emerald, #0a7c4c); transform-origin: 14px 14px;
  animation: iga-chat-sweep 1.4s ease-in-out infinite alternate; }
@keyframes iga-chat-sweep { from { transform: rotate(-70deg); } to { transform: rotate(70deg); } }
.iga-chat-askform label { display: block; font-weight: 600; margin-block-end: .3rem; }
.iga-chat-askrow { display: flex; gap: .5rem; }
.iga-chat-askrow input { flex: 1; min-inline-size: 0; min-block-size: 44px; padding-inline: .75rem;
  border: 1px solid var(--p-line-2); font: inherit; color: var(--p-ink); background: var(--p-paper); }
.iga-chat-askrow button { flex: none; inline-size: 44px; block-size: 44px; border: 0; cursor: pointer;
  background: var(--p-ink); color: var(--p-paper); display: inline-flex; align-items: center; justify-content: center; }
.iga-chat-askrow button:hover { background: var(--p-ink-2); }
.iga-chat-askrow button[disabled] { opacity: .55; cursor: progress; }
.iga-chat-askform .iga-chat-note { margin: .35rem 0 0; }
@media (prefers-reduced-motion: reduce) {
  .iga-chat { transition: none; }
  .iga-chat-needle { animation: none; }
}
@media (forced-colors: active) { .iga-chat-lift, .iga-chat-tear { display: none; } }
/* A phone: the panel takes the whole width and the whole height it can, so a
   form field is never narrower than its label — and the lift, which needs the
   room under the panel, is not drawn. It still rises from the bottom edge. */
@media (max-width: 520px) {
  .iga-chat { --lift: 0px; inset-inline: 0; inset-block-end: 0; inline-size: 100%; max-block-size: 100vh; }
  .iga-chat-lift { display: none; }
}
@media print { .iga-chat, .iga-chat-launch { display: none !important; } }

/* The admin enquiries list: each submission's own fields, label over value. */
dl.kv { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: .15rem .8rem; }
dl.kv dt { font-weight: 600; }
dl.kv dd { margin: 0; overflow-wrap: anywhere; white-space: pre-line; }

/* Home: the three cards under the hero (Arie, 27.9.2026). The poster is square;
   it is shown whole (contain), never cropped — it carries text. */
.home-feature img { inline-size: 100%; aspect-ratio: 1; object-fit: contain;
  background: var(--p-ink, #111); margin-block-end: .7rem; }
.home-feature h2 { font-size: 1.15rem; margin: 0 0 .4rem; }
.home-feature .pub-more { margin-block-start: auto; }

/* עובדים זרים: the per-role grid. It scrolls whole on a narrow screen. */
.fw-roles-wrap { overflow-x: auto; }
.fw-roles { border-collapse: collapse; inline-size: 100%; table-layout: fixed; font-size: 14px; }
.fw-roles th, .fw-roles td { border: 1px solid var(--p-line); padding: .4rem .5rem; text-align: start; }
.fw-roles thead th { font-weight: 600; }
/* Inputs fill their cell so the three number columns line up with their
   headings; the areas sit in columns instead of one tall list. */
.fw-roles input { inline-size: 100%; min-inline-size: 5rem; box-sizing: border-box; }
.fw-areas { display: grid; gap: .2rem 1.2rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); }
/* A refused submit (UI-FRM-04): the message under its field, a red edge, and
   a summary at the top whose links jump to each. Colour is never the only
   signal — the text says what to type. */
.pub-field-err { display: block; margin-block-start: .3rem; font-size: 13px; font-weight: 500; color: var(--p-red); }
.pub-field.is-invalid input { border-color: var(--p-red); }
.pub-err-summary { margin-block: 0 1rem; padding: .8rem 1rem; border: 1px solid var(--p-red);
  border-inline-start-width: 3px; background: var(--p-paper); }
.pub-err-summary p { margin: 0 0 .4rem; font-weight: 600; }
.pub-err-summary ul { margin: 0; padding-inline-start: 1.2rem; }
.pub-err-summary a { color: var(--p-red); }
/* The garage-name autocomplete: a list under the field, the MoT register's
   name / number / town on each row. */
.fw-suggest { position: relative; }
.fw-suggest .pub-field { margin: 0; }
.fw-suggest-hint { margin: .3rem 0 0; font-size: 12.5px; color: var(--p-ink-3); }
.fw-suggest-list { position: absolute; z-index: 5; inset-inline: 0; margin: 2px 0 0; padding: 0; list-style: none;
  max-block-size: 18rem; overflow-y: auto; background: var(--p-paper); border: 1px solid var(--p-line-2);
  box-shadow: 0 6px 20px rgb(0 0 0 / .12); }
.fw-suggest-list li { display: flex; justify-content: space-between; gap: .8rem; padding: .55rem .75rem;
  cursor: pointer; font-size: 14px; border-block-end: 1px solid var(--p-line); }
.fw-suggest-list li:last-child { border-block-end: 0; }
.fw-suggest-list li[aria-selected="true"], .fw-suggest-list li:hover { background: var(--p-wash); }
.fw-suggest-list .fw-s-meta { color: var(--p-ink-3); font-size: 12.5px; white-space: nowrap; }
.fw-filled { display: block; margin-block-start: .3rem; font-size: 12.5px; color: var(--p-brand-text); }

/* בחירות 2026 (/elections-2026): three dated rows the association has yet to
   fill, the bylaws' clauses quoted as they are, and the forms. */
.elections-lead { max-inline-size: 72ch; color: var(--p-ink-3); }
.elections-schedule { margin: 0 0 1.4rem; border-block-start: 1px solid var(--p-line); }
.elections-row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .3rem 1rem;
  padding-block: .7rem; border-block-end: 1px solid var(--p-line); break-inside: avoid; }
.elections-row dt { font-weight: 500; }
.elections-row dd { margin: 0; color: var(--p-ink-3); }
.elections-basis { display: block; font-size: 13px; font-weight: 400; color: var(--p-ink-3); }
.elections-clause { margin: 0 0 .9rem; padding: .7rem 1rem; border-inline-start: 2px solid var(--p-brand-text);
  background: var(--p-wash); break-inside: avoid; }
.elections-clause p { margin: 0 0 .4rem; }
.elections-clause footer { font-size: 13px; color: var(--p-ink-3); }
.elections-note { color: var(--p-ink-3); }
