/* =====================================================================
 * Kafel korepetytora na listingu (/matematyka, /szukaj).
 *
 * Wartosci wprost ze specyfikacji ("Pelna lista elementow ze stylami CSS").
 * Hexy w fallbackach var() sa te z tabeli specyfikacji — jesli arkusz tokenow
 * (payment_checkout_tokens.css) sie nie zaladuje, kafel dalej wyglada tak samo.
 *
 * Uklad na gridzie, a nie na zagniezdzonych flexach ze specyfikacji: to samo
 * DOM musi dac zdjecie na PELNA wysokosc kafla (desktop, razem z pasmem
 * opinii) oraz pasek CTA na dole (mobile). Flexy wymagalyby dwoch kopii
 * markupu albo przenoszenia elementow JS-em. Wymiary i odstepy pozostaja
 * zgodne ze specyfikacja.
 *
 * Nazewnictwo .ot- (offer tile), zeby nie zderzac sie z .offer-* z main.css.
 * ===================================================================== */

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

/* Kroj, wagi i kolory MUSZA byc wymuszone na dzieciach: main.css nadaje
   font-family i color bezposrednio na h3, p, a i button, wiec dziedziczenie
   z .ot sie urywalo — kafel dostawal Roboto (tylko do wagi 500, wiec 600/700
   szly sztucznym pogrubieniem) i zielone linki zamiast ciemnego tekstu. */
.ot h1, .ot h2, .ot h3, .ot h4,
.ot p, .ot a, .ot span, .ot b,
.ot button, .ot input { font-family: inherit; }

.ot {
	/* minmax(0, 1fr), nie samo 1fr: 1fr znaczy minmax(auto, 1fr), a to auto nie
	   pozwala kolumnie zejsc ponizej szerokosci tresci — dlugie nazwy wychodzily
	   przez to poza kafel zamiast konczyc sie wielokropkiem. */
	display: grid;
	grid-template-columns: 196px minmax(0, 1fr) auto;
	grid-template-areas:
		"photo name  name"
		"photo info  cta"
		"photo reviews reviews";
	background: var(--bg-surface, #ffffff);
	border: 1px solid var(--border-subtle, #e2e7e5);
	border-radius: var(--radius-lg, 12px);
	box-shadow: var(--shadow-sm, 0 1px 2px rgba(22, 30, 28, .06));
	overflow: hidden;             /* przycina zdjecie do zaokraglonych rogow */
	margin-bottom: 16px;          /* --space-4 */
	font-family: var(--font-sans, "Myriad Pro", Myriad, "Source Sans 3", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif);
	color: var(--text-primary, #161e1c);
	/* Wygladzanie subpikselowe pogrubia litery na jasnym tle — na kaflu tekst
	   wygladal przez to ciezej niz w makiecie mimo tych samych wag. */
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	cursor: pointer;
	position: relative;
	transition: box-shadow 150ms var(--ease-out, ease-out), border-color 150ms var(--ease-out, ease-out);
}

/* Hover tylko przy kursorze — na dotyku potrafi sie "zaciac" po tapnieciu
   i kafel zostaje podswietlony. Bez skalowania (spec). */
@media (hover: hover) {
	.ot:hover {
		box-shadow: var(--shadow-md, 0 4px 12px rgba(22, 30, 28, .1));
		border-color: var(--border-default, #c8d0ce);
	}
}

/* --- wyroznione (premium) ---
   Zielony pasek przy lewej krawedzi, jak w starym kaflu. Jako border-left,
   a nie ::before: pasek zajmuje wtedy WLASNE miejsce i tresc zaczyna sie za
   nim, zamiast byc przez niego zaslaniana. Przy nakladce absolutnej pasek
   kladl sie na zdjeciu, bo to ono zaczyna kafel. */
.ot--featured {
	border-left: 5px solid var(--brand-500, #2db994);
	box-shadow: 0 2px 5px rgba(0, 0, 0, .2);
}

/* --- zdjecie --- */

/* Kwadrat, nie pelna wysokosc kafla. Wszystkie zdjecia w serwisie sa 1:1,
   wiec w kwadratowym slocie cover nie ma czego przycinac — logotypy firm
   zostaja w calosci, a portrety wygladaja jak dotad. Rozciaganie na cala
   wysokosc wymagalo scinania bokow albo paskow gora-dol.
   UWAGA: przy proporcji 5/6 i kwadratowych zrodlach cover znowu scina boki
   (o ok. 20 procent szerokosci) — logotypy firm traca skrajne litery. Znika to
   dopiero, gdy zrodla tez beda 5/6 albo gdy slot wroci do kwadratu.
   align-self: start, bo zdjecie ma zostac przy gornej krawedzi, gdy tresc
   obok jest wyzsza. */
.ot-photo {
	grid-area: photo;
	display: block;
	align-self: start;
	aspect-ratio: 5 / 6;
	background: var(--gray-100, #eef1f0);
}

/* cover — na wyrazna decyzje. Zdjecia sa kwadratowe, a slot pionowy, wiec
   boki sa lekko przycinane i logotypy firm moga tracic skrajne litery.
   Wersja z contain (bez przycinania, z paskami gora-dol) byla probowana
   i odrzucona.
   Bylo: contain, bo wszystkie zdjecia sa kwadratowe (1:1),
   a slot jest pionowy (196 px szerokosci na pelna wysokosc kafla), wiec cover
   musial skalowac kwadrat do wysokosci slotu i scinal boki. Przy portretach
   bylo to niewidoczne, ale logotypy firm traca wtedy pierwsza i ostatnia
   litere nazwy (ATEMATIKO zamiast MATEMATIKON).
   Przy kwadratowych zrodlach contain nie jest kompromisem: kazdy obrazek
   dostaje ten sam, przewidywalny pasek gora-dol w kolorze tla slotu
   i nic sie nie obcina. */
.ot-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* --- naglowek --- */

.ot-info {
	grid-area: info;
	padding: 10px 0 16px 24px;
	min-width: 0;                 /* bez tego dlugi tekst rozpycha kolumne */
}

/* Wiersz nazwiska. flex-wrap sprawia, ze pigulka, gdy juz sie nie miesci,
   schodzi do drugiej linii i staje przy LEWEJ krawedzi nazwiska. Przy ukladzie
   inline zaczynala sie tam, gdzie skonczyl sie ostatni wyraz, plus wciecie. */
/* Naglowek to WLASNY grid o trzech kolumnach: nazwisko, pigulka, cena.
   Lokalizacja lezy w drugim wierszu i SCALA dwie pierwsze kolumny, wiec
   konczy sie tam, gdzie zaczyna sie cena, i nigdy pod nia nie wchodzi.
   Cena scala oba wiersze trzeciej kolumny, wiec stoi wysrodkowana wzgledem
   calego naglowka, a nie tylko wzgledem linii z nazwiskiem.
   Kolumna nazwiska to minmax(0, auto) — zero jako minimum pozwala jej oddac
   miejsce pigulce i cenie, dzieki czemu dluga nazwa konczy sie wielokropkiem
   zamiast rozpychac wiersz. */
.ot-head {
	grid-area: name;
	display: grid;
	grid-template-columns: minmax(0, auto) auto 1fr;
	grid-template-areas:
		"name pill price"
		"loc  loc  price";
	align-items: center;
	column-gap: 10px;
	padding: 20px 24px 0;
	min-width: 0;
}

/* min-width:0 na elemencie flex jest konieczne — bez tego nie zszedlby
   ponizej szerokosci swojej tresci i wielokropek nigdy by sie nie pojawil. */
.ot-head .ot-name {
	min-width: 0;
	overflow: hidden;
}

.ot-head .ot-name a {
	display: block;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ot-head .ot-pill { grid-area: pill; }

/* 600, a nie 500: nazwisko to glowna kotwica kafla i ma byc wyrazniejsze niz
   reszta naglowka. Ta sama waga co cena i ocena, wiec skala akcentow na
   kaflu zostaje spojna (500 uzywaja elementy drugoplanowe: pigulki, linki). */
.ot-name { grid-area: name; margin: 0; font-size: 19px; font-weight: 600; line-height: 1.3; }

.ot .ot-name,
.ot .ot-name a,
.ot .ot-name a:hover,
.ot .ot-name a:focus { color: var(--text-primary, #161e1c); text-decoration: none; }

/* --- pigulka aktywnosci --- */

.ot-pill {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	/* bez margin-left i vertical-align — odstep i wyrownanie daje grid naglowka (.ot-head) */
	padding: 3px 10px;
	border-radius: var(--radius-pill, 999px);
	font-size: 11.5px;
	font-weight: 500;
	line-height: 1.4;
	white-space: nowrap;
	vertical-align: middle;
	position: relative;
	top: -1px;
}

.ot-pill::before {
	content: "";
	width: 7px;
	height: 7px;
	border-radius: 50%;
	flex: 0 0 auto;
}

.ot-pill--fresh { background: var(--success-100, #d8f4ec); color: var(--brand-700, #1d8a6e); }
.ot-pill--fresh::before { background: var(--brand-500, #2db994); }

.ot-pill--stale { background: var(--gray-100, #eef1f0); color: var(--text-secondary, #5a6664); }
.ot-pill--stale::before { background: var(--gray-400, #a3adab); }

/* --- lokalizacja --- */

.ot-loc {
	grid-area: loc;
	margin: 5px 0 0;
	display: flex;
	align-items: center;
	gap: 6px;
	min-width: 0;
	font-size: 13px;
	line-height: 1.4;
}
.ot .ot-loc { color: var(--text-secondary, #5a6664); }

.ot-loc svg {
	width: 15px;
	height: 15px;
	flex: 0 0 auto;
	stroke: var(--gray-400, #a3adab);
	fill: none;
	stroke-width: 2;
}

/* --- opis: dwie linie i koniec --- */

.ot-desc {
	margin: 0;
	font-size: 13px;
	/* Jawne 400: main.css trzyma teksty w listingu na lzejszej wadze, a opis
	   i cytat wygladaly przez to za cienko obok reszty kafla. */
	font-weight: 400;
	line-height: 1.5;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
}
.ot .ot-desc { color: var(--text-secondary, #5a6664); }

/* --- cena --- */

/* Bez wlasnego paddingu — cena siedzi w gridzie naglowka, ktory ma juz swoj.
   Zostal tu po czasach, gdy byla polem grida ZEWNETRZNEGO, i spychal ja w dol,
   przez co stawka za godzine wychodzila pod krawedz naglowka.
   align-self: center dosuwa ja do srodka scalonych dwoch wierszy. */
.ot-price {
	grid-area: price;
	align-self: center;
	margin-left: auto;
	padding: 0;
	text-align: right;
	white-space: nowrap;
	line-height: 1.2;
}

/* 17, nie 19: przy 19 cena byla dokladnie tej samej wielkosci co nazwisko
   i walczyla z nim o uwage na obu koncach naglowka. Nazwisko zostaje
   glownym akcentem (19/600), cena schodzi o stopien nizej, ale trzyma
   te sama wage, wiec dalej czyta sie jako informacja pierwszoplanowa.
   Mobile ma wlasne 15 px i zostaje bez zmian. */
.ot-price b { font-size: 17px; font-weight: 600; color: var(--text-primary, #161e1c); }
.ot-price span { display: block; margin-top: 2px; font-size: 11px; color: var(--text-tertiary, #7c8886); }

/* --- przyciski --- */

.ot-cta {
	grid-area: cta;
	display: flex;
	/* stretch, nie flex-end: oba przyciski dostaja wtedy wysokosc rzedu, wiec
	   sa rowne niezaleznie od tego, co ktores z nich probuje sobie narzucic.
	   Przy flex-end kazdy liczyl wysokosc sam i <button> wychodzil o 1 px
	   nizszy od <a> mimo height i box-sizing z !important. */
	align-items: center;
	/* Rzad nie wypelnia calej komorki grida, wiec bez tego siedzialby przy jej
	   gornej krawedzi — a ma stac na srodku wzgledem opisu obok. */
	align-self: center;
	/* Korekta optyczna: srodek geometryczny wypada odrobine za wysoko wzgledem
	   dwoch linii opisu. Przez position, a nie margines, zeby nie ruszac
	   wysokosci komorki. */
	position: relative;
	top: 4px;
	justify-content: flex-end;
	gap: 8px;
	padding: 0 24px 16px;
}

.ot-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 40px;
	/* Padding i ramka wspolne dla obu przyciskow. Specyfikacja dawala 16 px
	   ghostowi i 18 px primary, a primary bez ramki — przez to "Zadzwon" byl
	   wezszy i o 2 px nizszy w srodku. Primary dostaje ramke w swoim kolorze,
	   wiec geometria obu jest identyczna. */
	padding: 0 18px;
	border: 1px solid transparent;
	border-radius: var(--radius-md, 8px);
	font-size: 13px;
	font-weight: 500;
	line-height: 1;
	white-space: nowrap;
	cursor: pointer;
	text-decoration: none;
	transition: background-color 150ms var(--ease-out, ease-out);
}

/* Pudelko obu przyciskow pinujemy regula o wysokiej specyficznosci (0,3,0).
   Samo .ot-btn przegrywalo z czyms w globalnych arkuszach i <button>
   "Zadzwon" wychodzil nizszy niz <a> "Wyslij wiadomosc" mimo height: 40px. */
.ot .ot-cta .ot-btn {
	/* Jedyne !important, ktore zostaje: .dip z fix.css ma padding: 0 5px
	   !important i inaczej nie da sie go przebic. Cala reszta wygrywa juz
	   sama specyficznoscia (0,3,0), odkad geometria .dip jest zneutralizowana
	   w regule ponizej. */
	box-sizing: border-box;
	height: 40px;
	padding: 0 18px !important;
	/* Bez ramki w modelu pudelka — obrys ghosta rysuje cien wewnetrzny, ktory
	   nie zajmuje miejsca, wiec oba przyciski maja identyczne pudelko
	   niezaleznie od tego, jaki box-sizing narzuci im ktorykolwiek arkusz. */
	border: 0;
	line-height: 1;
	font-size: 13px;
	font-weight: 500;
}
/* ZRODLO roznicy 1 px, szukane przez kilka podejsc: fix.css ma
   .dip { position: relative; top: -1px; margin-left: 2px; padding: 0 5px !important }
   Klasa .dip jest na przycisku Zadzwon, bo obsluguje popup z numerem —
   nie mozemy jej zdjac z markupu, wiec neutralizujemy jej geometrie tutaj.
   To ona wymuszala wszystkie !important w tym bloku. */
.ot .ot-cta .ot-btn.dip {
	position: static;
	top: auto;
	margin-left: 0;
	width: auto !important;
}

.ot .ot-cta .ot-btn--ghost { box-shadow: inset 0 0 0 1px var(--border-default, #c8d0ce); }
.ot .ot-cta .ot-btn--primary { box-shadow: none; }

.ot-btn:hover, .ot-btn:focus { text-decoration: none; }
.ot-btn:focus-visible { box-shadow: var(--shadow-focus, 0 0 0 3px rgba(45, 185, 148, .4)); outline: none; }

.ot-btn--ghost {
	background: var(--bg-surface, #ffffff);
	border: 1px solid var(--border-default, #c8d0ce);
	color: var(--text-primary, #161e1c);
}
.ot-btn--ghost:hover { background: var(--gray-50, #f6f8f7); color: var(--text-primary, #161e1c); }

/* Kontrast bieli na --brand-500 jest ponizej AA — swiadoma decyzja do czasu
   rebrandingu (spec), nie poprawiamy lokalnie. */
.ot-btn--primary {
	background: var(--brand-500, #2db994);
	border-color: var(--brand-500, #2db994);
	color: var(--text-on-brand, #ffffff);
}
.ot-btn--primary:hover { background: var(--brand-600, #25a282); color: var(--text-on-brand, #ffffff); }

/* --- odkryty numer telefonu ---
   Po kliknieciu "Zadzwon" skrypt DIP wstawia numer do tego spana i chowa
   przycisk. Stary kafel mial na to reguly w listing.css pod .offer-cta —
   nowy ma .ot-cta, wiec numer zostawal goly: podkreslony link w domyslnym
   kolorze, bez gabarytu przycisku, przez co rzad CTA sie rozjezdzal.
   Ten sam gabaryt co przycisk, zeby po odkryciu nic nie skakalo. */
.ot .ot-cta .offer-cta-phone {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	height: 40px;
	padding: 0 18px;
	border: 1px solid var(--brand-500, #2db994);
	border-radius: var(--radius-md, 8px);
	background: var(--success-100, #d8f4ec);
	color: var(--brand-700, #1d8a6e);
	font-size: 14px;
	font-weight: 600;
	letter-spacing: .03em;
	white-space: nowrap;
}

/* Pusty span nie moze rezerwowac miejsca przed odkryciem numeru. */
.ot .ot-cta .offer-cta-phone:empty { display: none; }

.ot .ot-cta .offer-cta-phone a,
.ot .ot-cta .offer-cta-phone a:hover,
.ot .ot-cta .offer-cta-phone a:focus {
	color: inherit;
	text-decoration: none;
}

/* --- pasmo opinii --- */

.ot-reviews {
	grid-area: reviews;
	display: flex;
	align-items: center;
	gap: 18px;
	padding: 12px 24px;
	background: var(--gray-50, #f6f8f7);
	border-top: 1px solid var(--border-subtle, #e2e7e5);
	min-width: 0;
}

/* Makieta: gwiazdki OBOK liczby, link "N opinii" pod nia. */
.ot-rate { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; }
.ot-rate-val { font-size: 23px; font-weight: 600; color: var(--text-primary, #161e1c); line-height: 1; }
.ot-rate-col { display: flex; flex-direction: column; gap: 3px; }

.ot-stars { display: flex; gap: 1px; }

/* Gwiazdki inline, bo /images/svg/star-on.svg ma wpisana na sztywno zielen
   serwisu — koloru z pliku nie da sie nadpisac CSS-em. */
.ot-star { width: 13px; height: 13px; display: block; fill: var(--warning-500, #d98a1c); }
.ot-star--off { fill: var(--gray-300, #dfe4e2); }

.ot .ot-count { font-size: 11px; font-weight: 500; color: var(--text-link, #1d8a6e); text-decoration: none; white-space: nowrap; }
.ot .ot-count:hover { color: var(--text-link-hover, #176b56); text-decoration: underline; }

.ot-sep { width: 1px; align-self: stretch; background: var(--border-subtle, #e2e7e5); flex: 0 0 auto; }

.ot-quote { flex: 1; min-width: 0; }

/* Cytat zawsze dwie linie — wysokosc pasma nie zalezy od dlugosci opinii. */
.ot-quote-text {
	margin: 0;
	font-size: 12.5px;
	font-weight: 400;
	line-height: 1.5;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
}
.ot .ot-quote-text { color: var(--text-secondary, #5a6664); }

/* Autor i data POZA clampem — nigdy nie zostaja przyciete. */
.ot-quote-meta { display: flex; align-items: center; gap: 10px; margin: 3px 0 0; font-size: 11.5px; }
.ot .ot-quote-meta { color: var(--text-tertiary, #7c8886); }

.ot .ot-more { font-size: 11.5px; font-weight: 500; color: var(--text-link, #1d8a6e); text-decoration: none; white-space: nowrap; }
.ot .ot-more:hover { color: var(--text-link-hover, #176b56); text-decoration: underline; }

.ot .ot-all { flex: 0 0 auto; align-self: center; font-size: 12px; font-weight: 500; white-space: nowrap; color: var(--text-link, #1d8a6e); text-decoration: none; }
.ot .ot-all:hover { color: var(--text-link-hover, #176b56); text-decoration: underline; }


/* ===================== WASKI DESKTOP / TABLET =====================
 * Specyfikacja zaklada kafel ~1100 px, ale kolumna listingu ma na zywo
 * 685-870 px (main.css: .offer-list-container, obok jest sidebar). W trzech
 * kolumnach na opis zostawalo ~150 px i lamal sie po dwa slowa, wiec ponizej
 * 1360 px — tam, gdzie main.css zwezа kontener — cena i przyciski schodza pod
 * opis. Zdjecie dalej trzyma pelna wysokosc. */
@media (min-width: 768px) and (max-width: 1359px) {

	/* Makieta 7a - tablet i maly desktop. Zdjecie full-bleed po lewej, na cala
	   wysokosc karty; prawa strona to dane, opinia w ramce i CTA. Bez opisu:
	   dzieki temu kolumna tresci jest nizsza od slotu 5:6, wiec to zdjecie
	   wyznacza wysokosc kafla i pod nim nie zostaje szpara. */
	.ot {
		grid-template-columns: 176px minmax(0, 1fr);
		grid-template-areas:
			"photo name"
			"photo reviews"
			"photo cta";
	}

	.ot-info { display: none; }

	/* Full-bleed wygrywa z proporcja na tym breakpoincie: makieta 7a chce
	   zdjecia dotykajacego gory i dolu karty, a tresc obok (dane + ramka opinii
	   + CTA) jest wyzsza niz slot 5:6 przy kolumnie 176 px. Przy align-self:
	   start zostawalaby pod zdjeciem biala szpara, wiec tutaj slot sie rozciaga,
	   a proporcje absorbuje object-fit: cover. */
	.ot-photo {
		align-self: stretch;
		/* aspect-ratio MUSI tu zniknac. Przy stretch wysokosc staje sie
		   definitywna, a wtedy proporcja liczy SZEROKOSC z wysokosci: 264.6 * 5/6
		   = 220.5 px przy kolumnie 176 px. Zdjecie wystawalo przez to o 44.5 px
		   poza swoja kolumne i wchodzilo pod ramke opinii. Bez proporcji szerokosc
		   dyktuje kolumna, a kadrowanie zalatwia object-fit: cover. */
		aspect-ratio: auto;
	}

	.ot-head { padding: 20px 24px 0; }

	.ot-price { padding: 0; text-align: right; }
	.ot-price span { display: inline; margin-left: 4px; }

	/* Opinia jako osadzona ramka, a nie pasmo przez cala szerokosc karty. */
	.ot-reviews {
		display: block;
		margin: 14px 24px 0;
		padding: 12px 16px;
		background: var(--gray-50, #f6f8f7);
		border: 1px solid var(--border-subtle, #e2e7e5);
		border-radius: var(--radius-md, 8px);
	}

	.ot-sep { display: none; }

	/* Uklad ramki wg makiety 8d:
	     wiersz 1 — ocena, gwiazdki i licznik w JEDNEJ linii
	     wiersz 2 — cytat, a obok niego, dosuniety do prawej i wyrownany
	                do dolu, link "Wszystkie opinie" (laduje przez to na
	                wysokosci podpisu cytatu, bez zgadywania marginesow)
	   flex-wrap zamiast grida, bo podpis cytatu siedzi WEWNATRZ .ot-quote
	   i nie da sie go ustawic jako osobnego pola siatki. */
	.ot-reviews {
		display: flex;
		flex-wrap: wrap;
		align-items: baseline;
		column-gap: 16px;
	}
	.ot-reviews .ot-rate { flex: 0 0 100%; }
	/* baza 0, nie auto: przy auto cytat domagal sie swojej pelnej szerokosci
	   i wypychal link do nowego wiersza (zmierzone przy 900 px). Z baza 0
	   kurczy sie i link zostaje na wysokosci podpisu. */
	.ot-reviews .ot-quote { flex: 1 1 0; min-width: 0; }
	.ot-reviews .ot-all { margin-left: auto; align-self: flex-end; }

	/* 23 px to skala desktopowego pasma, gdzie ocena stoi samotnie w lewej
	   kolumnie. W osadzonej ramce jest najwiekszym tekstem na kaflu — wiekszym
	   niz nazwisko i cena (19 px). Makieta ma tu wielkosc zblizona do licznika. */
	.ot-reviews .ot-rate-val { font-size: 15px; }
	.ot-reviews .ot-rate-col { flex-direction: row; align-items: center; gap: 8px; }

	/* CTA dosuniete do prawej krawedzi, pod ramka opinii. */
	.ot-cta { justify-content: flex-end; padding: 14px 24px 16px; }
}


/* =========================== MOBILE =========================== */

@media (max-width: 767px) {

	/* Ten sam zabieg co na tablecie: zdjecie rozciaga sie na wysokosc bloku
	   tekstu, wiec pod nim nie zostaje szpara (bylo 6 px). aspect-ratio musi
	   zniknac - przy stretch wysokosc jest definitywna i proporcja liczylaby
	   z niej szerokosc, wypychajac zdjecie poza kolumne 110 px. Kadruje cover. */
	.ot-photo {
		align-self: stretch;
		aspect-ratio: auto;
		/* Obrazek wyjety z ukladu, inaczej to ON wnosi wysokosc slotu - a wnosi
		   ja wedlug proporcji PLIKU. Przy zrodle 5:6 slot mialby 132 px, czyli
		   mniej niz blok tekstu (139 px), i szpara by wrocila. Absolutne inset:0
		   sprawia, ze wysokosc dyktuje wiersz grida, niezaleznie od zdjecia. */
		position: relative;
	}

	.ot-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

	.ot {
		/* 114 px, a nie 110: przy proporcji 5/6 szerokosc kolumny wyznacza
		   wysokosc zdjecia, a 110 px dawalo 137.5 px - o 4.5 px za malo, zeby
		   siegnac linii nad paskiem CTA. Zostawala biala szpara pod zdjeciem.
		   Blok tekstu obok ma stala wysokosc (nazwisko i lokalizacja maja nowrap
		   z wielokropkiem, wiec nie zawijaja sie niezaleznie od dlugosci), wiec
		   ta liczba jest deterministyczna, a nie dobrana pod jeden przypadek.
		   Od 113.6 px w gore zdjecie jest wyzsze od tresci i to ono wyznacza
		   wysokosc wierszy - czyli styka sie z linia zawsze. */
		grid-template-columns: 110px minmax(0, 1fr);
		grid-template-areas:
			"photo name"
			"photo info"
			"reviews reviews"
			"cta     cta";
		cursor: auto;
	}

	/* Zdjecie ma sztywne 5:6 i rozpina sie na wiersze name + info. Opis nie jest
	   na mobile pokazywany (makieta 3a: nazwisko, pigulka, lokalizacja, cena),
	   ale .ot-info dalej zajmowalo kilka pikselow - i o te kilka pikseli wiersz
	   name+info byl wyzszy od zdjecia, wiec pod zdjeciem zostawala szpara.
	   Bez tego wiersza blok tresci konczy sie rowno ze zdjeciem (132 px). */
	.ot-info { display: none; }




	/* Na telefonie naglowek to JEDNA kolumna. Przy trzech kolumnach (nazwisko,
	   pigulka, cena) kolumna nazwiska ma minmax(0, auto), wiec przy 375 px
	   oddawala cale miejsce pigulce i cenie i nazwisko znikalo pod wielokropkiem.
	   Kolejnosc jak na makiecie: nazwisko, pigulka, lokalizacja, cena. */
	.ot-head {
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas:
			"name"
			"pill"
			"loc"
			"price";
		align-items: start;
		column-gap: 0;
		padding: 11px 16px 0;
		/* Zdjecie ma sztywne 5:6 (110x132) i konczy sie na swojej wysokosci, wiec gdy
		   naglowek byl nizszy, pod zdjeciem zostawala szpara. min-height rowne
		   szerokosci slotu sprawia, ze obie sekcje koncza sie w tym samym
		   miejscu, a odstepy nizej sa docisniete, zeby naglowek tych 110 px
		   nie przekraczal. */
		min-height: 138px;   /* 110 * 5/4 — wysokosc slotu przy proporcji 5/6 */
	}

	/* Pola grida wypelniaja teraz kolumne, wiec nazwisko jest wezsze od
	   swojej tresci i moze sie skrocic wielokropkiem. Pigulka i cena maja
	   przylegac do tresci, stad justify-self: start tylko na nich. */
	.ot-head .ot-pill { margin-top: 4px; justify-self: start; }
	.ot-head .ot-loc { margin-top: 5px; }

	/* Cena wraca do lewej i pod lokalizacje — margin-left: auto z desktopu
	   dosunelby ja do prawej krawedzi. */
	.ot-head .ot-price {
		align-self: start;
		justify-self: start;
		margin: 5px 0 0;
		text-align: left;
	}
	/* Opis jest na telefonie ukryty, wiec .ot-info nie ma czego pokazywac —
	   zostawal po nim sam padding, czyli kilkupikselowa szpara pod zdjeciem. */
	.ot-info { padding: 0; }

	/* Pigulka na osobnej linii — przy 375 px nie miesci sie obok nazwiska. */
	.ot-name { font-size: 16px; }
	.ot-pill { top: 0; font-size: 11px; padding: 2px 9px; }
	.ot-pill::before { width: 6px; height: 6px; }

	.ot-loc { margin-top: 6px; gap: 5px; font-size: 12px; }
	.ot-loc svg { width: 13px; height: 13px; }

	/* Opisu nie pokazujemy na telefonie (spec). */
	.ot-desc { display: none; }

	.ot-price {
		padding: 0;
		text-align: left;
	}
	.ot-price b { font-size: 15px; }
	.ot-price span { display: inline; margin-left: 4px; }

	/* Pasmo opinii: ocena w jednej linii, cytat pod spodem. */
	.ot-reviews { display: block; padding: 10px 16px; }

	.ot-rate { gap: 6px; align-items: center; }

	/* Jedna gwiazdka, nie piec — specyfikacja mobilna mowi
	   "gwiazdka + 4,9 + link opinii w jednej linii", tak jest tez
	   na makiecie. */
	.ot-stars .ot-star:not(:first-child) { display: none; }
	.ot-rate-val { font-size: 13px; }
	.ot-rate-col { flex-direction: row; align-items: center; gap: 6px; }
	.ot .ot-count { font-size: 12px; }
	.ot-sep { display: none; }
	.ot .ot-all { display: none; }   /* rolе linku przejmuje caly klikalny kafel */

	.ot-quote-text { margin-top: 5px; font-size: 12px; }
	.ot-quote-meta { margin-top: 3px; font-size: 11px; }
	.ot .ot-more { font-size: 11px; }

	.ot-cta {
		/* Zdejmujemy korekte optyczna z desktopu (position: relative; top: 4px).
		   Tam CTA stoi w rzedzie obok opisu i te 4 px wyrownuja je optycznie do
		   dwoch linii tekstu. Tutaj CTA jest paskiem na cala szerokosc z wlasna
		   linia u gory, wiec ten sam offset spychal pasek RAZEM Z LINIA w dol -
		   pod zdjeciem zostawala biala szpara, a pasek wystawal 3 px poza kafel.
		   align-self tez wraca do domyslnego, bo w pasku na cala szerokosc nie ma
		   czego centrowac. */
		position: static;
		top: auto;
		align-self: stretch;
		padding: 12px 16px;
		border-top: 1px solid var(--border-subtle, #e2e7e5);
		gap: 8px;
	}

	/* 44 px — cel dotykowy. */

	.ot .ot-cta .ot-btn { height: 44px; padding: 0 12px !important; }
	.ot .ot-cta .offer-cta-phone { height: 44px; flex: 1 1 0; padding: 0 12px; }
	.ot-btn--ghost { flex: 1 1 0; }
	.ot-btn--primary { flex: 1.4 1 0; }
}

/* Brak zdjecia — placeholder z design systemu zamiast inicjalow ad hoc. */
.ot-photo--empty img { object-fit: contain; padding: 14%; opacity: .55; }

/* ============ PUNKTY WYROZNIENIA (zalogowany korepetytor) ============
   Ikona pioruna przy cenie + czarny tooltip z pelna wartoscia.
   Uwaga na selektory: .ot-price span ma display:block i font-size:11px,
   wiec kazda regula tooltipa musi byc scopowana przez .ot-price, inaczej
   przegrywa specyficznoscia i dymek rozjezdza sie w blok pod cena. */
.ot-price .ot-dp {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	margin-right: 6px;
	padding: 0;
	align-self: center;
	vertical-align: middle;
	background: var(--warning-100, #fbe8c9);
	border: 1px solid var(--warning-500, #d98a1c);
	border-radius: 50%;
	cursor: pointer;
	line-height: 0;
}

.ot-price .ot-dp-ico { width: 14px; height: 14px; fill: var(--warning-500, #d98a1c); }

/* Na listingu <b> z cena siedzi w <span itemprop="offers"> (mikrodane), a
   .ot-price span ma display:block — przez to cena spadala pod ikone i pod
   "/ 60 min" robil sie trzeci wiersz. Regula .ot-price span jest szersza,
   niz zakladal jej autor: lapie tez opakowanie schema.org, nie tylko czas
   trwania lekcji. Przywracamy mu inline, zeby ikona i cena byly w linii. */
.ot-price [itemprop="offers"] { display: inline; }

/* Ikona ma stac dokladnie w osi z cena. vertical-align:middle tego nie robi:
   liczy sie wzgledem metryk fontu RODZICA (.ot-price), a cena ma wlasne 19 px,
   wiec ikona siadala 2,5 px nizej — stale na kazdej szerokosci.

   Flex na calym .ot-price nie wchodzil w gre: z flex-wrap ikona spadala pod
   cene przy waskiej kolumnie (zmierzone przy 800 px, a takze przy 1360 px,
   gdy dlugie nazwisko sciska kolumne ceny), a bez wrap nie dalo sie zostawic
   "/ 60 min" we wlasnym wierszu powyzej 1359 px. Dlatego flex obejmuje
   WYLACZNIE ikone i cene, a "/ 60 min" zostaje poza nim i zachowuje swoje
   dotychczasowe zachowanie. Wyrownanie srodkami pudelek nie zalezy od kroju,
   wiec nie rozjedzie sie, gdy przegladarka podstawi inny font. */
.ot-price .ot-price-main {
	display: inline-flex;
	/* baseline, nie center: cena i "/ 60 min" maja rozne rozmiary czcionki,
	   wiec tylko wspolna linia bazowa rowna ich dolne krawedzie. Ikona nie ma
	   tekstu, wiec jej baseline byloby dolna krawedzia pudelka — dostaje
	   osobno align-self: center, zeby zostac w osi z cena. */
	align-items: baseline;
	vertical-align: middle;
}

/* "/ 60 min" w tej samej linii co cena na KAZDEJ szerokosci. Bazowa regula
   .ot-price span { display: block } lamala wiersz powyzej 1359 px (nizej byla
   juz nadpisana na inline), przez co ten sam kafel wygladal inaczej na
   szerokim desktopie niz na tablecie. Selektor omija .ot-price-main, wiec
   opakowanie ikony z cena zostaje przy swoim inline-flex, a wariant
   "cena do ustalenia" siedzi w srodku opakowania i tez go nie dotyczy. */
.ot-price .ot-price-unit {
	/* .ot-price span daje mu 11 px i szarosc — zostawiamy, zerujemy tylko
	   margin-top: 2px stamtad, bo jako element flexa juz DZIALA i zbijalby
	   linie bazowa o te 2 px. */
	margin: 0 0 0 4px;
}

.ot-price .ot-dp-tip {
	/* nadpisujemy .ot-price span (display:block, 11px, szary) */
	display: block;
	position: absolute;
	/* W DOL, nie w gore. Kafel ma overflow:hidden (przycina zdjecie do
	   zaokraglonych rogow), a na desktopie cena jest pierwszym wierszem
	   naglowka — dymek otwierany do gory wychodzil 3-6 px poza kafel i byl
	   przez to ucinany. Pod cena miejsca jest az nadto. */
	top: calc(100% + 9px);
	/* prawa krawedz dymka rowna prawej krawedzi ikony */
	right: -6px;
	left: auto;
	z-index: 20;
	margin: 0;
	padding: 7px 11px;
	background: #1f2937;
	border-radius: 8px;
	color: #fff;
	font-size: 12.5px;
	font-weight: 400;
	line-height: 1.3;
	text-align: left;
	white-space: nowrap;
	box-shadow: 0 6px 18px rgba(16, 24, 40, .22);
	opacity: 0;
	visibility: hidden;
	transition: opacity .12s ease;
}

.ot-price .ot-dp-tip b { color: #fff; font-size: inherit; font-weight: 700; }

/* dzióbek */
.ot-price .ot-dp-tip::after {
	content: "";
	position: absolute;
	bottom: 100%;
	right: 12px;
	border: 5px solid transparent;
	border-bottom-color: #1f2937;
}

/* Desktop/tablet: najechanie. :hover tylko tam, gdzie kursor faktycznie
   istnieje — na dotyku :hover potrafi sie zablokowac po tapnieciu. */
@media (hover: hover) {
	.ot-price .ot-dp:hover .ot-dp-tip,
	.ot-price .ot-dp:focus-visible .ot-dp-tip { opacity: 1; visibility: visible; }
}

/* Dotyk: klasa z offer_tile.js po tapnieciu */
.ot-price .ot-dp.is-open .ot-dp-tip { opacity: 1; visibility: visible; }

/* ======================= MOBILE =======================
   Dwie roznice wzgledem desktopu.

   1. Ikona ZA cena. W DOM stoi przed nia (tak ma byc na desktopie), wiec
      przestawiamy ja samym order — .ot-price staje sie flexem tylko w tym
      celu. Kolejnosc zrodlowa reszty zostaje, bo maja domyslny order: 0.

   2. Dymek w GORE. Na desktopie cena jest pierwszym wierszem naglowka i do
      gory bylby ucinany przez overflow:hidden kafla — dlatego tam otwiera
      sie w dol. Na telefonie naglowek to jedna kolumna, w ktorej cena jest
      wierszem OSTATNIM, wiec w gore dymek laduje nad lokalizacja, czyli
      wciaz wewnatrz kafla. W dol nie moze, bo tam konczy sie slot zdjecia.
      Tooltip jest position:absolute, wiec w zadna strone nie zmienia
      wysokosci naglowka — sprawdzone pomiarem (otwarty i zamkniety daja
      identyczne min-height 138 px, wiec pod zdjeciem nie robi sie szpara). */
@media (max-width: 767px) {
	/* order dziala wewnatrz .ot-price-main, ktore i tak jest flexem — .ot-price
	   zostaje blokiem, zeby "/ 60 min" zachowalo swoje zachowanie. */
	/* Cena przy LEWEJ krawedzi, ikona wypchnieta na koniec wiersza i dosunieta
	   do PRAWEJ krawedzi ramki. Opakowanie musi byc pelnej szerokosci flexem,
	   bo inline-flex konczy sie na tresci i nie ma czego rozpychac. Kolejnosc
	   przestawia order: cena (0), czas (2), ikona (3). */
	/* .ot-head .ot-price ma justify-self: start, wiec pole grida kurczy sie do
	   tresci — bez stretch opakowanie nie ma czego wypelnic i margin-left:auto
	   przy ikonie nie robi nic. */
	.ot-head .ot-price { justify-self: stretch; }

	.ot-price .ot-price-main {
		display: flex;
		width: 100%;
	}

	.ot-price .ot-price-unit { order: 2; }

	.ot-price .ot-dp {
		order: 3;
		margin-right: 0;
		/* auto zjada cala wolna przestrzen miedzy czasem a ikona */
		margin-left: auto;
	}

	.ot-price .ot-dp-tip {
		top: auto;
		bottom: calc(100% + 9px);
		/* Ikona nie stoi juz przy lewej krawedzi kafla, tylko za cena, wiec
		   kotwica do prawej trzyma dymek z dala od prawej krawedzi ekranu. */
		left: auto;
		right: -6px;
		/* width: max-content jest konieczne: element absolutny liczy szerokosc
		   od containing blocku, czyli od 26-pikselowej ikony — bez tego dymek
		   zwijal sie do trzech linii ("Punkty / wyroznienia: / 124 500"). */
		width: max-content;
		max-width: calc(100vw - 32px);
		white-space: normal;
	}

	.ot-price .ot-dp-tip::after {
		bottom: auto;
		top: 100%;
		right: 12px;
		left: auto;
		border-bottom-color: transparent;
		border-top-color: #1f2937;
	}
}

/* Cena wyrownana GORA z nazwiskiem i pigulka.
   Domyslnie .ot-price ma align-self: center, a rozpina sie na dwa wiersze
   grida (nazwisko + lokalizacja), wiec jej srodek wypadal miedzy nimi —
   tekst ceny siedzial 13,9 px nizej niz nazwisko.

   align-self: start rownia PUDELKA (oba startuja na 20,0 px), ale tekst ceny
   zostawal 4 px nizej: nazwisko ma 19 px i line-height 1.3, cena 17 px i 1.2,
   wiec ich pudelka wierszy zaczynaja sie w innych miejscach. Te 4 px zdejmuje
   korekta — wartosc dobrana pomiarem, nie na oko: przy -4px rozjazd wynosi
   dokladnie 0,0 px przy 1400, 1100 i 900 px, zarowno z ikona punktow, jak
   i bez niej (ikona nie ma z tym nic wspolnego — sprawdzone osobno).

   Tylko od 768 px: nizej cena jest osobnym wierszem grida z wlasnymi
   regulami i przesuniecie by ja rozjechalo. */
@media (min-width: 768px) {
	.ot-price {
		align-self: start;
		position: relative;
		top: -4px;
	}
}
