Schedules to the Act (First & Second) and high-yield Rule schedules (C, G, H, H1, J, K, M, P, T, X, Y) Import of drugs — Section 10 prohibited classes, licensing/permit flowchart, and verified Section 13 penalty table (imprisonment/fine figures) Manufacture of drugs — Section 18 prohibitions (with flowchart), licence conditions (Schedule M/GMP), and the four special licence types (Test/Analysis, New Drug, Loan, Repacking) with a comparison flowchart Section 27 penalty ladder (3→7→10 years to life) — verified against the actual bare act text A consolidated manufacture-to-sale compliance flowchart Mnemonics throughout (MASque, MASt-P-New, TeNo-Lo-Re, 3-3-7

Reading File
Finding Sources
Searching the Web

Drugs and Cosmetics Act 1940 Section 27 penalty ladder Schedule H H1 X import manufacture provisions bare act

Reading Web Page

https://cdsco.gov.in/opencms/export/sites/CDSCO_WEB/Pdf-docu…

Finding Sources
Finding Sources
Finding Sources
Finding Sources
Searching the Web

Drugs Cosmetics Act 1940 Section 10 prohibited drugs list Section 18 manufacture prohibition First Schedule Second Schedule drugs list India

Reading File
Reading Web Page

https://ayush.delhi.gov.in/sites/default/files/ayush/custom/…

Now I have enough material to construct a comprehensive, high-yield answer. Let me compile everything.
Reading File
I now have comprehensive data from the bare Act (CDSCO/India Code official PDFs), the Forensic Medicine textbook, and the Karnataka Penalty table. Let me now produce the complete high-yield study guide.

Drugs and Cosmetics Act, 1940 - Complete High-Yield Study Guide

Sources: Bare Act text (CDSCO official PDF, India Code), Drugs & Cosmetics Rules 1945, The Essentials of Forensic Medicine & Toxicology 36e (2026), Karnataka Drugs Control Dept Penalty Table

PART 1 - THE SCHEDULES (First, Second + Rule Schedules)

First Schedule - Books of Standards (Section 3(b))

The First Schedule lists the official pharmacopoeias and formularies whose standards define "standard quality" under the Act. Key entries:
EntryReference Text
Pharmacopoeia of India (IP)Official Indian standard
British Pharmacopoeia (BP)Applies to drugs described therein
International Pharmacopoeia (IP/WHO)WHO standard
Extra Pharmacopoeia (Martindale)Reference for unlisted drugs
United States Pharmacopeia (USP)Applicable where specified
British Pharmaceutical Codex (BPC)Additional standard
British Veterinary CodexVeterinary drugs
Ayurvedic Pharmacopoeia of IndiaAYUSH drugs
Siddha Vaidya Thirattu / Unani PharmacopoeiaAYUSH system drugs
Mnemonic - "I BIG BBA US" = IP, BP, International Pharma, German Pharmacopoeia, British Vet Codex, British Pharma Codex, Ayurvedic/Siddha/Unani, USP

Second Schedule - Standards of Quality

Lists the specific standards for drugs manufactured/imported - purity, potency, and test methods. Any drug whose standard is in the Second Schedule must fully comply or it is deemed substandard under Section 16. A fixed-dose combination of a Second Schedule drug with an Ayurvedic drug is explicitly prohibited under Section 10A notifications.

High-Yield Rule Schedules (Drugs & Cosmetics Rules 1945)

Mnemonic: "MASque, C-G, H-H1, J-K, M-P, T-X-Y"
ScheduleWhat it ContainsKey Requirement
CBiological & special products (vaccines, sera, toxoids, hormones, antibiotics injectables)Enhanced storage/cold chain; manufacturing under stricter conditions
C1Large-volume parenteralsGMP + separate manufacturing
G~65 drugs (antihistamines, insulin, bleomycin, aminopterine, cytotoxics)Label must carry: "CAUTION - For use only under medical supervision"
HPrescription-only drugs (antibiotics, steroids, antihypertensives, etc.)Only on RMP prescription; entry in prescription register mandatory
H1High-risk Rx drugs (3rd/4th gen cephalosporins, carbapenems, fluoroquinolones, anti-TB, antifungals)Red strip on label; prescription retained by chemist for 2 years; cannot be repeated without fresh Rx
JDiseases for which no drug may claim to be a cure54 diseases listed (cancer, AIDS, diabetes, etc.); any such claim = misbranding
KDrugs exempt from Chapters IV/IVA in certain states/areas (Ayurveda, homeopathy)Limited applicability
MGood Manufacturing Practice (GMP) standards for premises, plant, machinery, personnelMandatory compliance for all licensed manufacturers (Schedule M = Indian GMP)
M-IIIGMP for cosmeticsSeparate GMP code
PLife period of drugs - storage period/shelf-life guidelinesGoverns expiry dating
TStandards for surgical dressings, bandages, orthopaedic implantsQuality standards for these categories
XHabit-forming / psychotropic drugs (morphine, pethidine, fentanyl, codeine formulations)Strict licence (Form 20-A); dispensing only on special Rx; records kept 2 years; no advertisement
YRequirements for clinical trials (data to be submitted)Preclinical + clinical data package for new drug approval
Quick mnemonic "C Gets High - H1 too, Just Keep Making Perfectly True eXtra Years": C(biological), G(caution label), H(Rx), H1(red strip+retain Rx), J(no-cure claims), K(exempt drugs), M(GMP), P(shelf life), T(surgical standards), X(habit-forming), Y(clinical trial data)

PART 2 - IMPORT OF DRUGS (Chapter III)

Section 10 - Prohibited Classes (The "MASque" List)

Mnemonic: "MASque" = Misbranded, Adulterated, Spurious, quality-substandard, extra-prohibited
Section 10 prohibits import of any drug that is:
┌─────────────────────────────────────────────────────────────┐
│  SECTION 10 - PROHIBITED DRUG IMPORTS                       │
├─────────────────────────────────────────────────────────────┤
│  (a) Not of standard quality (below First/Second Schedule)  │
│  (b) Misbranded (Section 9 definition)                      │
│  (c) Adulterated (Section 9A definition)                    │
│  (d) Spurious (Section 9B definition)                       │
│  (ee) Cosmetic tested on animals [post-2014 amendment]      │
│  (f) Without valid import licence (Form 10)                 │
│  (g) Any drug notified by CG under Section 10A as dangerous │
│       or lacking therapeutic value                          │
└─────────────────────────────────────────────────────────────┘
Section 10A - Central Government can prohibit ANY drug by notification in the Official Gazette if it:
  • Is likely to cause risk to human beings/animals
  • Lacks claimed therapeutic value
  • Contains ingredients with no therapeutic justification
Notable Section 10A-prohibited drugs (historical notifications): Nialamide, Practolol, Amidopyrin, Phenacetin, Methapyrilene, Methaqualone, Chloral hydrate, Analgin combinations, Dextropropoxyphene combinations

Import Licensing - Flowchart

INTENDING IMPORTER
        │
        ▼
  Is drug in Section 10 prohibited list?
        │
   YES ──────────────────────────────────► IMPORT PROHIBITED
        │                                  (unless special permit)
       NO
        │
        ▼
  Obtain Licence from Central Licensing Authority (CLA / CDSCO)
  ┌─────────────────────────────────────┐
  │  Form 10  → Regular import licence  │
  │  Form 11  → Import for examination/ │
  │             test/analysis only      │
  │  Form 8   → Import of new drugs     │
  │             (requires clinical data)│
  └─────────────────────────────────────┘
        │
        ▼
  Special Exceptions (Rule 33/33A):
  ┌──────────────────────────────────────────────────────┐
  │ Rule 33   - Small quantities for Test/Analysis       │
  │             (licence Form 11 required)               │
  │ Rule 33-A - New drugs for life-threatening diseases  │
  │             (Govt hospital / autonomous institution) │
  │ Rule 136  - Cosmetics for personal use (baggage)     │
  └──────────────────────────────────────────────────────┘
        │
        ▼
  Labelling compliance: Parts IX, X, XII of Rules
  (Name, manufacturer, expiry, country of origin mandatory)
        │
        ▼
  CUSTOMS CLEARANCE (Section 11 applies Sea Customs Act 1878)

Section 13 - Penalty Table (Verified Against Bare Act)

ClauseOffenceImprisonmentFine
13(1)(a)Import of adulterated/spurious drug (Sec 9A/9B) OR animal-tested cosmetic (Sec 10, cl. ee)Up to 3 yearsUp to ₹5,000
13(1)(b)Import of any other prohibited drug/cosmetic (Sec 10)Up to 6 monthsUp to ₹500, OR both
13(1)(c)Import in contravention of Section 10A notificationUp to 3 yearsUp to ₹5,000, OR both
13(2) subsequent offenceRepeat conviction under 13(1)(a)Up to 7 yearsUp to ₹5,000
Note: Fine figures are from the original 1940 text and have not been updated by recent amendments unlike Section 27 fines - low fine values in Section 13 vs. Section 27 are a deliberate exam trap.

PART 3 - MANUFACTURE OF DRUGS (Chapter IV)

Section 18 - Prohibitions (The "7-Arm" List)

Mnemonic: "No MSA-P-N-L-C" = No Misbranded, Spurious, Adulterated, Patent/Proprietary (unlabelled formula), New drug without approval, Licence without compliance, Contraband manufacture
Section 18 prohibits any person from manufacturing for sale, distributing, selling, stocking, or exhibiting:
┌────────────────────────────────────────────────────────────────┐
│  SECTION 18(a) - PROHIBITED MANUFACTURE/SALE                   │
├────────────────────────────────────────────────────────────────┤
│  (i)   Drug not of standard quality / misbranded / adulterated │
│        / spurious                                              │
│  (ii)  Cosmetic not of standard quality / misbranded / spurious│
│  (iii) Patent/proprietary medicine without displaying true     │
│        formula or active ingredient list on label              │
│  (iv)  Drug without a valid licence under Section 18(c)        │
│  (v)   Drug in contravention of any condition of the licence   │
│  (vi)  Drug that is a New Drug without approval under Rule 122E│
│  (vii) Any drug in violation of any notified restriction       │
│        (Section 26A/26B)                                       │
└────────────────────────────────────────────────────────────────┘

SECTION 18(b) - BANNING ADVERTISEMENTS
  No drug advertisement claiming cure of a Schedule J disease

SECTION 18(c) - LICENCE MANDATORY
  No manufacture without a licence granted by Licensing Authority
  (Licence under Rule 68/69 for allopathic drugs)
Section 18 Manufacture Prohibition Flowchart:
WANT TO MANUFACTURE A DRUG FOR SALE?
             │
             ▼
  Step 1: Is it a New Drug (Rule 122E)?
             │
         YES ──► Get Central Govt approval (CDSCO New Drug Approval)
             │        + Clinical trial data (Schedule Y)
            NO
             │
             ▼
  Step 2: Is it a standard quality drug (First/Second Schedule)?
             │
          NO ──► PROHIBITED under Sec 18(a)(i)
             │
           YES
             │
             ▼
  Step 3: Apply for Manufacturing Licence
      ┌────────────────────────────────────────┐
      │  State Licensing Authority (SLA)       │
      │  Application in Form 24 (allopathic)   │
      │  Premises inspection                   │
      │  GMP compliance (Schedule M)           │
      └────────────────────────────────────────┘
             │
             ▼
  Step 4: Licence granted → Form 25 (allopathic)
             │
             ▼
  Step 5: Ongoing compliance:
      - Schedule M (GMP) at all times
      - Qualified Person (QP) on premises
      - Testing (in-house or approved lab)
      - Records / Schedule U compliance
      - Annual returns
             │
             ▼
  MANUFACTURE PERMITTED

Schedule M - GMP Requirements (Key Points)

Schedule M sets out Good Manufacturing Practices covering:
  1. Buildings & Premises - adequate space, clean room classifications, segregated areas for quarantine/sampling/manufacturing/dispensing/finished goods
  2. Equipment - validated, calibrated, material-appropriate (stainless steel where required)
  3. Personnel - Qualified Person must be present; training records; health surveillance
  4. Sanitation & Hygiene - SOPs for cleaning, pest control, gowning
  5. Documentation - Batch Manufacturing Records (BMR), Standard Operating Procedures (SOPs), Batch Packing Records
  6. Quality Control - In-process testing, release testing, reference samples kept for 3 years (or 3 months post-expiry for expiry-dated drugs)
  7. Self-Inspection - Periodic internal audits
  8. Complaints & Recalls - Written procedures mandatory
Schedule M-III covers GMP specifically for cosmetic manufacture.

The Four Special Licence Types

Mnemonic: "TeNo-Lo-Re" = Test/analysis, New drug, Loan licence, Repacking licence
Licence TypeFormWho AppliesKey Features
Test/Analysis Licence (Rule 33/Form 11 for import; Form 24 category for manufacture)Form 11 (import)Research labs, analytical labsOnly small quantities; drug cannot be used commercially; test facility must be specified; Inspector access mandatory
New Drug Licence (Rule 122E/Form 44)Form 44Manufacturer of a New DrugRequires Phase I-III clinical trial data (Schedule Y); CDSCO (Central) approval mandatory; not State SLA
Loan Licence (Rule 69A/Form 25A)Form 25ACompany that owns the formula but lacks its own manufacturing plantUses another's licensed premises + equipment; licensor must hold valid Form 25; if licensor's licence cancelled/suspended → loan licence automatically cancelled/suspended
Repacking Licence (Rule 74A/Form 25B)Form 25BCompany that buys bulk drug and repackagesQualified competent person must supervise at all times; facility must have testing arrangements; no alteration of drug substance permitted
Special Licence Comparison Flowchart:
SPECIAL MANUFACTURE SITUATION?
          │
    ┌─────┴──────┐
    │            │
    ▼            ▼
Do you have    Do you have
your own       your own
premises?      formula?
    │               │
   NO              NO
    │               │
    ▼               ▼
LOAN LICENCE    TEST/ANALYSIS
(Form 25A)      LICENCE
                (Form 11/24)
    │
   YES (have premises but no formula)
    │
    ▼
REPACKING LICENCE
(Form 25B)
    │
Is it a brand new drug (Rule 122E)?
    │
   YES
    │
    ▼
NEW DRUG LICENCE
(Form 44, CDSCO Central)
Key distinction for exams:
  • Loan licence (25A) = own formula, borrow premises
  • Repacking (25B) = own premises, handle bulk from another manufacturer
  • New Drug (44) = Central approval only (not State SLA)
  • Test/Analysis = non-commercial, Inspector access compulsory

PART 4 - SECTION 27 PENALTY LADDER

Verified Against Bare Act (CDSCO Official PDF + India Code)

Section 27 applies to: manufacture for sale, distribution, sale, stocking, exhibiting or distributing drugs in contravention of Chapter IV.
Mnemonic: "3-3-7-10-Life" ladder
═══════════════════════════════════════════════════════════════════
                    SECTION 27 PENALTY LADDER
═══════════════════════════════════════════════════════════════════

  Sec 27(d)  │ Any other contravention (not falling in a/b/c)
             │ e.g. licence condition breach, labelling error
             │ ► Imprisonment up to 1 YEAR
             │ ► Fine ≥ ₹20,000
             │   (Court may reduce below 1 yr on recorded reasons)
─────────────────────────────────────────────────────────────────
  Sec 27(c)  │ Adulterated drug (Sec 17A) not likely to cause
             │ death/harm BUT quality below standard
             │ ► Imprisonment: 1 to 3 YEARS + fine ≥ ₹50,000
─────────────────────────────────────────────────────────────────
  Sec 27(b)  │ Spurious drug (Sec 17B) OR drug failing standard
             │ NOT causing/likely to cause death or grievous hurt
             │ ► Imprisonment: NOT < 7 YEARS, up to LIFE
             │ ► Fine ≥ ₹3 lakh OR 3x value of drugs (whichever
             │   more)
             │   Proviso: Court may impose < 7 yrs / < ₹1 lakh
             │   for adequate and special recorded reasons
─────────────────────────────────────────────────────────────────
  Sec 27(a)  │ Adulterated (Sec 17A) or Spurious (Sec 17B) drug
  [HIGHEST]  │ WHICH CAUSES/IS LIKELY TO CAUSE DEATH or GRIEVOUS
             │ HARM when used for treatment/prevention/diagnosis
             │ ► Imprisonment: NOT < 10 YEARS, up to LIFE
             │ ► Fine ≥ ₹10 lakh OR 3x value of drugs confiscated
             │   (whichever more)
             │   Proviso: Court may impose < 10 yrs for adequate/
             │   special reasons recorded in judgment
═══════════════════════════════════════════════════════════════════
Section 30 - Subsequent Offence Enhancement:
Previous convictionRepeat punishment
Under Sec 27(b) (spurious, no death)7 years → NOT < 7 yrs, up to 10 years + fine ≥ ₹2 lakh
Under Sec 27(c) (adulterated, no death)NOT < 10 yrs, up to LIFE + fine ≥ ₹3 lakh
Under Sec 27(d) (other contravention)→ NOT < 2 years, up to 4 years OR fine ≥ ₹50,000, or both
Memory Hook - "3-7-10-Life":
  • "3" = minimum for Sec 27(c) type offences in subsequent conviction context
  • "7" = minimum for Sec 27(b) (spurious without death)
  • "10" = minimum for Sec 27(a) (spurious/adulterated causing death/grievous hurt)
  • "Life" = maximum for both Sec 27(a) and 27(b)

PART 5 - CONSOLIDATED MANUFACTURE-TO-SALE COMPLIANCE FLOWCHART

Mnemonic: "MASt-P-New" = Manufacture licence, Approved premises, Standard quality drugs, testing, Packaging/labelling, New drug approval if needed
══════════════════════════════════════════════════════════════════
            MANUFACTURE → DISTRIBUTION → SALE COMPLIANCE
══════════════════════════════════════════════════════════════════

[A] PRE-MANUFACTURE STAGE
  ┌─────────────────────────────────────────────────────────┐
  │  Is it a NEW DRUG (Rule 122E)?                          │
  │      YES → CDSCO approval + Schedule Y data (Phase I-III│
  │              clinical trials) → Form 44 (New Drug Lic.) │
  │      NO  → Proceed to [B]                               │
  └─────────────────────────────────────────────────────────┘

[B] LICENSING (Sec 18(c), Rule 68-69)
  ┌─────────────────────────────────────────────────────────┐
  │  Apply to STATE Licensing Authority (SLA)               │
  │  Form 24 → Inspection → Schedule M GMP compliance       │
  │  Qualified Person (QP) on site                          │
  │  Form 25 GRANTED                                        │
  │                                                         │
  │  OR Special licences:                                   │
  │    Loan (25A) / Repacking (25B) / Test (Form 11)        │
  └─────────────────────────────────────────────────────────┘

[C] MANUFACTURE (Schedule M compliance)
  ┌─────────────────────────────────────────────────────────┐
  │  → GMP premises (Schedule M)                            │
  │  → QP present throughout                                │
  │  → Batch Manufacturing Record (BMR) maintained          │
  │  → In-process quality checks                            │
  │  → Quarantine of finished goods pending QC release      │
  └─────────────────────────────────────────────────────────┘

[D] QUALITY CONTROL & TESTING
  ┌─────────────────────────────────────────────────────────┐
  │  → Test against First/Second Schedule standards         │
  │  → Government Analyst testing (Sec 20-25)               │
  │  → Reference samples retained:                          │
  │     - 3 yrs (no expiry date on label)                   │
  │     - 3 months beyond expiry date                       │
  │  → Batch release certificate by QP                      │
  └─────────────────────────────────────────────────────────┘

[E] LABELLING & PACKAGING (Parts IX, X of Rules)
  ┌─────────────────────────────────────────────────────────┐
  │  → Manufacturer name + address                          │
  │  → Batch No., Date of manufacture, Expiry date          │
  │  → Schedule-specific labels:                            │
  │     Sch G  → "CAUTION - Medical supervision only"       │
  │     Sch H  → "Rx" symbol                                │
  │     Sch H1 → RED STRIP across top                       │
  │     Sch X  → Special markings + Form 20-A dispensing    │
  │  → Patent medicine → list all active ingredients        │
  │  → No false claims (Sch J disease cure prohibition)     │
  └─────────────────────────────────────────────────────────┘

[F] DISTRIBUTION
  ┌─────────────────────────────────────────────────────────┐
  │  → Wholesale licence (Form 20/21)                       │
  │  → Cold chain for Schedule C drugs                      │
  │  → Records: invoice, stock register maintained          │
  └─────────────────────────────────────────────────────────┘

[G] RETAIL SALE
  ┌─────────────────────────────────────────────────────────┐
  │  → Retail licence (Form 20)                             │
  │  → Registered Pharmacist on premises                    │
  │  → Prescription register for Sch H, H1, X drugs        │
  │  → Sch H1 prescription retained 2 years                 │
  │  → Sch X: no repeat dispensing without fresh Rx         │
  │  → No Sch H/H1/X without valid prescription             │
  └─────────────────────────────────────────────────────────┘

[H] PENALTIES IF NON-COMPLIANT
  ┌─────────────────────────────────────────────────────────┐
  │  Manufacture violation → Sec 27(a/b/c/d) ladder         │
  │  Import violation      → Sec 13 ladder                  │
  │  Subsequent offences   → Sec 30 (enhanced penalties)    │
  │  Cognizable offence    → Spurious causing death (non-   │
  │                          bailable, cognizable)           │
  └─────────────────────────────────────────────────────────┘
══════════════════════════════════════════════════════════════════

PART 6 - MASTER MNEMONICS CHEATSHEET

MnemonicStands ForCovers
MASqueMisbranded, Adulterated, Spurious, quality-substandardProhibited drug categories (Sec 10 & Sec 18)
MASt-P-NewManufacture lic, Approved premises, Standard drugs, testing, Packaging, New drug licCompliance checklist Sec 18
TeNo-Lo-ReTest/analysis, New drug, Loan, Repacking4 special licence types
3-3-7-10-Life3 yrs (Sec 13/27c), 7 yrs (Sec 27b), 10 yrs (Sec 27a), LifePenalty ladder
C Gets HighC (biological), G (caution), H (Rx), H1 (red strip)Prescription schedules
J bans K M P T X YJ (Schedule J no-cure claims), K, M (GMP), P (shelf life), T (surgical), X (habit), Y (clinical trial)Rule Schedules reference

QUICK EXAM TRAPS & HIGH-YIELD POINTS

  1. Section 27 vs Section 13 fines - Sec 27 fines run into lakhs (₹10 lakh for death-causing drugs); Sec 13 fines are tiny (₹500-₹5,000) - often tested as a contrast
  2. Loan licence (25A) auto-cancellation - If the licensor's Form 25 is cancelled/suspended, the loan licensee's Form 25A is automatically cancelled. No separate notice needed.
  3. Schedule H1 = Red Strip (NOT red box, not red cross - it is a RED STRIP across the label top). Prescription must be RETAINED by the chemist for 2 years. Introduced by 2013 amendment targeting antibiotic resistance.
  4. New Drug approval = CDSCO (Central), NOT State SLA - A common exam distractor
  5. Section 18 proviso - Manufacture of small quantities for examination/test/analysis is EXEMPT from Section 18 restrictions (but requires licence under Section 18(c)/Rule 68)
  6. Section 27(a) threshold - "Likely to cause death OR grievous harm" - not actual death. If the spurious drug only MIGHT cause harm (established by evidence), Sec 27(a) applies.
  7. Cognizable & non-bailable - Offences involving spurious/adulterated drugs that cause death are cognizable (police can arrest without warrant) and non-bailable
  8. Schedule C drugs - Need extra conditions (cold chain, special containers), and their manufacture is regulated by the Central Licensing Authority (not State), unlike most other drugs
  9. No advertisement of Sch H/H1/X - Advertisement of these drugs requires prior sanction of the Central Government (Rule 74)
  10. Reference sample retention - 3 years (if no expiry date) vs 3 months beyond expiry - frequently tested in MCQs

All penalty figures verified against: CDSCO official PDF of the Act & Rules (2016 edition), India Code bare Act (indiacode.nic.in), and Karnataka Drugs Control Dept Penalty Table 2025. Section 27 fine amounts updated by 2008/2015 amendments: ₹10 lakh / ₹3 lakh minimums for clauses (a)/(b) respectively.

Act as professsor and prepare colorful notes handbook pdf of above note for students add flow chart diagrams

Reading File
Running Command

mkdir -p /home/daytona/workspace/dca-handbook && ls /home/daytona/workspace/dca-handbook

Prepare handbook pdf of above notes colorful

Running Command

mkdir -p /home/daytona/workspace/dca-handbook && python3 -c "import reportlab; print(reportlab.Version)"

Writing File

~/dca-handbook/generate_handbook.py

#!/usr/bin/env python3
"""
Drugs & Cosmetics Act 1940 - Student Handbook PDF Generator
Colorful, professor-style notes with flowcharts and tables
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    PageBreak, HRFlowable, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.graphics.shapes import (
    Drawing, Rect, String, Line, Polygon, Arrow,
    Group, Circle
)
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Drawing
from reportlab.platypus import Image
import io

# ─── COLOUR PALETTE ───────────────────────────────────────────────────────────
NAVY      = colors.HexColor("#1A237E")
BLUE      = colors.HexColor("#1565C0")
LTBLUE    = colors.HexColor("#E3F2FD")
TEAL      = colors.HexColor("#00695C")
LTTEAL    = colors.HexColor("#E0F2F1")
RED       = colors.HexColor("#B71C1C")
LTRED     = colors.HexColor("#FFEBEE")
ORANGE    = colors.HexColor("#E65100")
LTORANGE  = colors.HexColor("#FFF3E0")
PURPLE    = colors.HexColor("#4A148C")
LTPURPLE  = colors.HexColor("#F3E5F5")
GREEN     = colors.HexColor("#1B5E20")
LTGREEN   = colors.HexColor("#E8F5E9")
GOLD      = colors.HexColor("#F57F17")
LTGOLD    = colors.HexColor("#FFFDE7")
PINK      = colors.HexColor("#880E4F")
LTPINK    = colors.HexColor("#FCE4EC")
GREY      = colors.HexColor("#37474F")
LTGREY    = colors.HexColor("#ECEFF1")
WHITE     = colors.white
BLACK     = colors.black

W, H = A4

# ─── STYLES ───────────────────────────────────────────────────────────────────
base_styles = getSampleStyleSheet()

def S(name, **kw):
    return ParagraphStyle(name, **kw)

cover_title = S("CoverTitle", fontName="Helvetica-Bold", fontSize=28,
                textColor=WHITE, alignment=TA_CENTER, spaceAfter=8, leading=34)
cover_sub   = S("CoverSub",   fontName="Helvetica-Bold", fontSize=16,
                textColor=LTBLUE, alignment=TA_CENTER, spaceAfter=4)
cover_info  = S("CoverInfo",  fontName="Helvetica",      fontSize=11,
                textColor=WHITE, alignment=TA_CENTER, spaceAfter=3)

part_header = S("PartHeader", fontName="Helvetica-Bold", fontSize=20,
                textColor=WHITE, alignment=TA_CENTER, spaceAfter=0, leading=26)
section_hdr = S("SectionHdr", fontName="Helvetica-Bold", fontSize=14,
                textColor=WHITE, alignment=TA_LEFT, spaceAfter=0, leading=18)
sub_hdr     = S("SubHdr",     fontName="Helvetica-Bold", fontSize=12,
                textColor=NAVY, alignment=TA_LEFT, spaceAfter=4, spaceBefore=8)
body        = S("Body",       fontName="Helvetica",      fontSize=9.5,
                textColor=GREY, alignment=TA_JUSTIFY, spaceAfter=4, leading=14)
bullet_body = S("BulletBody", fontName="Helvetica",      fontSize=9.5,
                textColor=GREY, leftIndent=14, bulletIndent=4, spaceAfter=3, leading=13)
mnemonic    = S("Mnemonic",   fontName="Helvetica-Bold", fontSize=11,
                textColor=PURPLE, alignment=TA_CENTER, spaceAfter=4,
                backColor=LTPURPLE, borderPad=6, leading=15)
note_style  = S("Note",       fontName="Helvetica-Oblique", fontSize=9,
                textColor=ORANGE, alignment=TA_LEFT, spaceAfter=3, leading=13)
trap_style  = S("Trap",       fontName="Helvetica-Bold", fontSize=9.5,
                textColor=RED, alignment=TA_LEFT, spaceAfter=3, leading=13)
toc_item    = S("TocItem",    fontName="Helvetica",      fontSize=10,
                textColor=NAVY, spaceAfter=5, leading=14)
footer_sty  = S("Footer",     fontName="Helvetica-Oblique", fontSize=7.5,
                textColor=colors.HexColor("#90A4AE"), alignment=TA_CENTER)

# ─── HELPER FLOWABLES ─────────────────────────────────────────────────────────

class ColorBanner(Flowable):
    """A full-width coloured banner with white text."""
    def __init__(self, text, bg=NAVY, fg=WHITE, height=22, font_size=13, radius=4):
        Flowable.__init__(self)
        self.text = text
        self.bg = bg
        self.fg = fg
        self.bh = height
        self.font_size = font_size
        self.radius = radius
        self.width = W - 4*cm

    def wrap(self, aw, ah):
        self.width = aw
        return aw, self.bh + 4

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg)
        c.roundRect(0, 2, self.width, self.bh, self.radius, fill=1, stroke=0)
        c.setFillColor(self.fg)
        c.setFont("Helvetica-Bold", self.font_size)
        c.drawCentredString(self.width/2, 2 + self.bh/2 - self.font_size*0.35, self.text)


class SideBadge(Flowable):
    """A left-stripe coloured box (like a callout)."""
    def __init__(self, text, stripe=TEAL, bg=LTTEAL, width=None, min_height=18):
        Flowable.__init__(self)
        self.text = text
        self.stripe = stripe
        self.bg = bg
        self._w = width
        self.min_height = min_height

    def wrap(self, aw, ah):
        self._w = aw
        # Estimate height from text length
        chars_per_line = int(aw / 5.5)
        lines = max(1, len(self.text) // chars_per_line + 1)
        self._h = max(self.min_height, lines * 14 + 10)
        return aw, self._h

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg)
        c.rect(0, 0, self._w, self._h, fill=1, stroke=0)
        c.setFillColor(self.stripe)
        c.rect(0, 0, 5, self._h, fill=1, stroke=0)
        c.setFillColor(GREY)
        c.setFont("Helvetica", 9)
        c.drawString(10, self._h/2 - 4, self.text)


def colored_table(data, col_widths, header_bg=NAVY, header_fg=WHITE,
                  alt_bg=LTBLUE, border=BLUE, font_size=8.5):
    """Build a nicely styled table."""
    ts = TableStyle([
        ('BACKGROUND', (0,0), (-1,0), header_bg),
        ('TEXTCOLOR',  (0,0), (-1,0), header_fg),
        ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0), (-1,0), font_size),
        ('ALIGN',      (0,0), (-1,-1), 'LEFT'),
        ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
        ('FONTNAME',   (0,1), (-1,-1), 'Helvetica'),
        ('FONTSIZE',   (0,1), (-1,-1), font_size - 0.5),
        ('GRID',       (0,0), (-1,-1), 0.4, border),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, alt_bg]),
        ('LEFTPADDING',  (0,0), (-1,-1), 5),
        ('RIGHTPADDING', (0,0), (-1,-1), 5),
        ('TOPPADDING',   (0,0), (-1,-1), 4),
        ('BOTTOMPADDING',(0,0), (-1,-1), 4),
        ('WORDWRAP',   (0,0), (-1,-1), 1),
    ])
    t = Table(data, colWidths=col_widths, repeatRows=1)
    t.setStyle(ts)
    return t


def penalty_table(data, col_widths):
    ts = TableStyle([
        ('BACKGROUND', (0,0), (-1,0), RED),
        ('TEXTCOLOR',  (0,0), (-1,0), WHITE),
        ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0), (-1,0), 8.5),
        ('ALIGN',      (0,0), (-1,-1), 'LEFT'),
        ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
        ('FONTNAME',   (0,1), (-1,-1), 'Helvetica'),
        ('FONTSIZE',   (0,1), (-1,-1), 8),
        ('GRID',       (0,0), (-1,-1), 0.4, RED),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LTRED]),
        ('LEFTPADDING',  (0,0), (-1,-1), 5),
        ('RIGHTPADDING', (0,0), (-1,-1), 5),
        ('TOPPADDING',   (0,0), (-1,-1), 4),
        ('BOTTOMPADDING',(0,0), (-1,-1), 4),
    ])
    t = Table(data, colWidths=col_widths, repeatRows=1)
    t.setStyle(ts)
    return t


# ─── FLOWCHART DRAWING HELPERS ────────────────────────────────────────────────

def make_box(d, x, y, w, h, text, bg, fg=WHITE, font_size=8, radius=5, border=None):
    border_c = border if border else bg
    d.add(Rect(x, y, w, h, rx=radius, ry=radius,
               fillColor=bg, strokeColor=border_c, strokeWidth=1))
    lines = text.split('\n')
    line_h = font_size + 2
    total_h = len(lines) * line_h
    start_y = y + h/2 + total_h/2 - line_h
    for line in lines:
        d.add(String(x + w/2, start_y, line,
                     fontName="Helvetica-Bold" if lines.index(line)==0 else "Helvetica",
                     fontSize=font_size, fillColor=fg,
                     textAnchor="middle"))
        start_y -= line_h


def arrow_down(d, x, y, length=18, color=GREY):
    d.add(Line(x, y, x, y - length + 5, strokeColor=color, strokeWidth=1.5))
    # arrowhead
    d.add(Polygon([x-4, y-length+7, x+4, y-length+7, x, y-length],
                  fillColor=color, strokeColor=color, strokeWidth=0.5))


def arrow_right(d, x, y, length=30, color=GREY):
    d.add(Line(x, y, x + length - 5, y, strokeColor=color, strokeWidth=1.5))
    d.add(Polygon([x+length-7, y-4, x+length-7, y+4, x+length, y],
                  fillColor=color, strokeColor=color, strokeWidth=0.5))


def make_diamond(d, cx, cy, w, h, text, bg=GOLD, fg=WHITE, font_size=7.5):
    hw, hh = w/2, h/2
    pts = [cx, cy+hh, cx+hw, cy, cx, cy-hh, cx-hw, cy]
    d.add(Polygon(pts, fillColor=bg, strokeColor=GREY, strokeWidth=1))
    lines = text.split('\n')
    line_h = font_size + 1.5
    start_y = cy + (len(lines)-1)*line_h/2
    for line in lines:
        d.add(String(cx, start_y, line, fontName="Helvetica-Bold",
                     fontSize=font_size, fillColor=fg, textAnchor="middle"))
        start_y -= line_h


# ─── FLOWCHART: IMPORT LICENSING ──────────────────────────────────────────────
def import_flowchart():
    dw, dh = 480, 340
    d = Drawing(dw, dh)
    d.add(Rect(0, 0, dw, dh, fillColor=LTBLUE, strokeColor=BLUE, strokeWidth=0.5))

    # Title
    d.add(String(dw/2, dh-16, "IMPORT LICENSING FLOWCHART (Sec 10 & Ch III)",
                 fontName="Helvetica-Bold", fontSize=9, fillColor=NAVY, textAnchor="middle"))

    # Start
    make_box(d, dw/2-55, dh-50, 110, 22, "INTENDING IMPORTER", NAVY, WHITE, 8)
    arrow_down(d, dw/2, dh-50, 18)

    # Diamond 1
    make_diamond(d, dw/2, dh-100, 160, 36,
                 "Drug in Sec 10\nprohibited list?", GOLD, WHITE, 7.5)

    # YES → PROHIBITED
    d.add(Line(dw/2+80, dh-100, dw/2+155, dh-100, strokeColor=RED, strokeWidth=1.5))
    d.add(Polygon([dw/2+153, dh-104, dw/2+153, dh-96, dw/2+160, dh-100],
                  fillColor=RED, strokeColor=RED))
    make_box(d, dw/2+160, dh-112, 100, 24, "IMPORT\nPROHIBITED", RED, WHITE, 8)
    d.add(String(dw/2+110, dh-97, "YES", fontName="Helvetica-Bold", fontSize=7, fillColor=RED))

    # NO arrow down
    arrow_down(d, dw/2, dh-118, 20)
    d.add(String(dw/2+4, dh-124, "NO", fontName="Helvetica-Bold", fontSize=7, fillColor=GREEN))

    # Licences box
    lic_y = dh - 180
    make_box(d, 60, lic_y, 360, 52,
             "OBTAIN IMPORT LICENCE from CDSCO (Central)\n"
             "Form 10 → Regular import  |  Form 11 → Test/Analysis\n"
             "Form 8  → New Drug import (+ Schedule Y data)",
             TEAL, WHITE, 8)
    arrow_down(d, dw/2, lic_y, 18)

    # Special exceptions
    exc_y = lic_y - 65
    make_box(d, 60, exc_y, 360, 52,
             "SPECIAL EXCEPTIONS (Rules 33, 33-A, 136)\n"
             "Rule 33   : Small qty for Test/Analysis (Form 11)\n"
             "Rule 33-A : New drug for life-threatening disease\n"
             "Rule 136  : Cosmetics for personal use (baggage)",
             PURPLE, WHITE, 8)
    arrow_down(d, dw/2, exc_y, 18)

    # Labelling
    label_y = exc_y - 38
    make_box(d, 100, label_y, 280, 24,
             "Labelling: Parts IX, X, XII compliance\n(Name, Manufacturer, Expiry, Country of Origin)",
             BLUE, WHITE, 8)
    arrow_down(d, dw/2, label_y, 18)

    # Final
    make_box(d, dw/2-70, label_y-40, 140, 24,
             "CUSTOMS CLEARANCE\n(Sec 11 - Sea Customs Act 1878)",
             GREEN, WHITE, 8)

    return d


# ─── FLOWCHART: SECTION 18 MANUFACTURE ───────────────────────────────────────
def manufacture_flowchart():
    dw, dh = 480, 380
    d = Drawing(dw, dh)
    d.add(Rect(0, 0, dw, dh, fillColor=LTGREEN, strokeColor=TEAL, strokeWidth=0.5))
    d.add(String(dw/2, dh-16, "SECTION 18 - MANUFACTURE PROHIBITION FLOWCHART",
                 fontName="Helvetica-Bold", fontSize=9, fillColor=TEAL, textAnchor="middle"))

    make_box(d, dw/2-80, dh-50, 160, 22, "WANT TO MANUFACTURE A DRUG FOR SALE?", NAVY, WHITE, 7.5)
    arrow_down(d, dw/2, dh-50, 18)

    # Diamond: New Drug?
    make_diamond(d, dw/2, dh-105, 170, 38, "New Drug\n(Rule 122E)?", ORANGE, WHITE, 7.5)
    # YES
    d.add(Line(dw/2+85, dh-105, dw/2+150, dh-105, strokeColor=ORANGE, strokeWidth=1.5))
    d.add(Polygon([dw/2+148, dh-109, dw/2+148, dh-101, dw/2+155, dh-105],
                  fillColor=ORANGE, strokeColor=ORANGE))
    make_box(d, dw/2+155, dh-119, 110, 28,
             "CDSCO Approval\n+ Schedule Y\n+ Form 44", ORANGE, WHITE, 7.5)
    d.add(String(dw/2+112, dh-102, "YES", fontName="Helvetica-Bold", fontSize=7, fillColor=ORANGE))

    arrow_down(d, dw/2, dh-124, 18)
    d.add(String(dw/2+4, dh-130, "NO", fontName="Helvetica-Bold", fontSize=7, fillColor=GREEN))

    # Diamond: Standard quality?
    make_diamond(d, dw/2, dh-180, 180, 38, "Standard Quality?\n(First/Second Schedule)", GOLD, WHITE, 7.5)
    d.add(Line(dw/2+90, dh-180, dw/2+155, dh-180, strokeColor=RED, strokeWidth=1.5))
    d.add(Polygon([dw/2+153, dh-184, dw/2+153, dh-176, dw/2+160, dh-180],
                  fillColor=RED, strokeColor=RED))
    make_box(d, dw/2+158, dh-192, 100, 24, "PROHIBITED\nSec 18(a)(i)", RED, WHITE, 8)
    d.add(String(dw/2+115, dh-177, "NO", fontName="Helvetica-Bold", fontSize=7, fillColor=RED))

    arrow_down(d, dw/2, dh-199, 16)
    d.add(String(dw/2+4, dh-205, "YES", fontName="Helvetica-Bold", fontSize=7, fillColor=GREEN))

    # Apply licence
    lic_y = dh - 262
    make_box(d, 50, lic_y, 380, 40,
             "Apply for Mfg Licence → State Licensing Authority (SLA)\n"
             "Form 24 | Premises Inspection | Schedule M (GMP)",
             TEAL, WHITE, 8)
    arrow_down(d, dw/2, lic_y, 18)

    # Licence granted
    lg_y = lic_y - 46
    make_box(d, 130, lg_y, 220, 22, "LICENCE GRANTED → Form 25", GREEN, WHITE, 8)
    arrow_down(d, dw/2, lg_y, 18)

    # Ongoing
    og_y = lg_y - 62
    make_box(d, 50, og_y, 380, 50,
             "ONGOING COMPLIANCE\n"
             "Schedule M (GMP) | QP on site | BMR records\n"
             "Quality testing | Annual returns | Sch U records",
             BLUE, WHITE, 8)
    arrow_down(d, dw/2, og_y, 16)

    make_box(d, dw/2-70, og_y-36, 140, 22, "MANUFACTURE PERMITTED", GREEN, WHITE, 8)

    return d


# ─── FLOWCHART: SPECIAL LICENCES ─────────────────────────────────────────────
def special_licence_flowchart():
    dw, dh = 480, 270
    d = Drawing(dw, dh)
    d.add(Rect(0, 0, dw, dh, fillColor=LTPURPLE, strokeColor=PURPLE, strokeWidth=0.5))
    d.add(String(dw/2, dh-16, "FOUR SPECIAL LICENCE TYPES  [TeNo-Lo-Re]",
                 fontName="Helvetica-Bold", fontSize=9, fillColor=PURPLE, textAnchor="middle"))

    top_y = dh - 50
    make_box(d, dw/2-75, top_y, 150, 22, "SPECIAL MANUFACTURE NEED?", NAVY, WHITE, 8)

    # Four branches
    box_y = top_y - 100
    positions = [30, 140, 260, 368]
    labels = [
        "TEST/ANALYSIS\nForm 11\nSmall qty only\nInspector access",
        "NEW DRUG\nForm 44\nCDSCO Central\nSchedule Y data",
        "LOAN LICENCE\nForm 25A\nOwn formula\nBorrow premises",
        "REPACKING\nForm 25B\nOwn premises\nBulk → repack"
    ]
    colors_list = [TEAL, ORANGE, BLUE, PURPLE]
    short = ["Te", "No", "Lo", "Re"]

    for i, (px, label, clr, sh) in enumerate(zip(positions, labels, colors_list, short)):
        # Line from centre
        d.add(Line(dw/2, top_y, px+50, top_y - 50, strokeColor=clr, strokeWidth=1.2,
                   strokeDashArray=[3,2]))
        make_box(d, px, box_y, 100, 68, label, clr, WHITE, 7.5)
        # Badge
        d.add(Rect(px+35, box_y+60, 30, 14, fillColor=GOLD, strokeColor=GOLD, rx=3, ry=3))
        d.add(String(px+50, box_y+63, sh, fontName="Helvetica-Bold",
                     fontSize=9, fillColor=WHITE, textAnchor="middle"))

    # Note
    d.add(String(dw/2, 18,
                 "Loan (25A): if licensor's Form 25 cancelled → 25A auto-cancelled",
                 fontName="Helvetica-Oblique", fontSize=7.5, fillColor=RED, textAnchor="middle"))

    return d


# ─── FLOWCHART: SECTION 27 PENALTY LADDER ────────────────────────────────────
def penalty_ladder_flowchart():
    dw, dh = 480, 310
    d = Drawing(dw, dh)
    d.add(Rect(0, 0, dw, dh, fillColor=LTRED, strokeColor=RED, strokeWidth=0.5))
    d.add(String(dw/2, dh-16, "SECTION 27 PENALTY LADDER  [3-7-10-LIFE]",
                 fontName="Helvetica-Bold", fontSize=9.5, fillColor=RED, textAnchor="middle"))

    rungs = [
        (dh-58,  LTGREY,  GREY,  "Sec 27(d)  Other contraventions (labelling/licence condition)\n"
                                   "Up to 1 Year  |  Fine ≥ ₹20,000"),
        (dh-118, LTORANGE, ORANGE,"Sec 27(c)  Adulterated drug — NOT causing death\n"
                                   "1 to 3 Years  |  Fine ≥ ₹50,000"),
        (dh-178, LTRED,   RED,   "Sec 27(b)  Spurious drug — NOT causing death/grievous hurt\n"
                                   "NOT < 7 Years, up to LIFE  |  Fine ≥ ₹3 lakh or 3× value"),
        (dh-248, colors.HexColor("#B71C1C"), WHITE,
                                   "Sec 27(a)  Adulterated/Spurious → CAUSES DEATH / GRIEVOUS HURT\n"
                                   "NOT < 10 Years, up to LIFE  |  Fine ≥ ₹10 lakh or 3× value"),
    ]

    for i, (y, bg, fg, text) in enumerate(rungs):
        # Rung number badge
        badge_c = [GREY, ORANGE, RED, colors.HexColor("#7B0000")][i]
        d.add(Rect(20, y, 30, 48, fillColor=badge_c, strokeColor=badge_c, rx=3, ry=3))
        d.add(String(35, y+20, str(i+1), fontName="Helvetica-Bold",
                     fontSize=18, fillColor=WHITE, textAnchor="middle"))
        # Main box
        d.add(Rect(58, y, dw-78, 48, fillColor=bg, strokeColor=badge_c,
                   strokeWidth=1.2, rx=4, ry=4))
        lines = text.split('\n')
        fy = y + 30
        for li, line in enumerate(lines):
            fn = "Helvetica-Bold" if li == 0 else "Helvetica"
            fc = fg if bg != LTGREY else GREY
            d.add(String(68, fy, line, fontName=fn, fontSize=8, fillColor=fc))
            fy -= 14

        # Arrow between rungs
        if i < len(rungs)-1:
            next_y = rungs[i+1][0]
            d.add(Line(dw/2, y, dw/2, next_y+48, strokeColor=colors.HexColor("#7B0000"),
                       strokeWidth=1.2))

    return d


# ─── FLOWCHART: MANUFACTURE TO SALE ──────────────────────────────────────────
def mfg_to_sale_flowchart():
    dw, dh = 480, 420
    d = Drawing(dw, dh)
    d.add(Rect(0, 0, dw, dh, fillColor=LTGOLD, strokeColor=GOLD, strokeWidth=0.5))
    d.add(String(dw/2, dh-16,
                 "CONSOLIDATED MANUFACTURE → SALE COMPLIANCE  [MASt-P-New]",
                 fontName="Helvetica-Bold", fontSize=9, fillColor=NAVY, textAnchor="middle"))

    stages = [
        (dh-50,  "A. PRE-MANUFACTURE",  "New Drug? → CDSCO + Sch Y + Form 44\nStandard Drug? → Proceed", NAVY),
        (dh-108, "B. LICENSING",        "SLA Form 24 → Inspection → Sch M GMP\nLicence Form 25 Granted", TEAL),
        (dh-166, "C. MANUFACTURE",      "GMP premises | QP present | BMR records\nIn-process QC | Batch quarantine", BLUE),
        (dh-224, "D. QUALITY CONTROL",  "Test vs First/Second Schedule | Govt Analyst\nRef samples: 3 yrs / 3 months post-expiry", PURPLE),
        (dh-282, "E. LABELLING",        "Sch G: CAUTION label  | Sch H: Rx symbol\nSch H1: RED STRIP     | Sch X: Special Rx", PINK),
        (dh-340, "F. DISTRIBUTION",     "Wholesale Lic Form 20/21 | Cold chain (Sch C)\nInvoice & stock register", ORANGE),
        (dh-390, "G. RETAIL SALE",      "Retail Lic Form 20 | Registered Pharmacist\nPrescription register for H/H1/X drugs", GREEN),
    ]

    for i, (y, stage, detail, clr) in enumerate(stages):
        # Stage tag
        d.add(Rect(10, y, 120, 46, fillColor=clr, strokeColor=clr, rx=4, ry=4))
        d.add(String(70, y+24, stage.split('.')[0] + '.', fontName="Helvetica-Bold",
                     fontSize=7.5, fillColor=WHITE, textAnchor="middle"))
        d.add(String(70, y+13, stage.split('. ', 1)[1], fontName="Helvetica-Bold",
                     fontSize=7.5, fillColor=WHITE, textAnchor="middle"))

        # Detail box
        d.add(Rect(138, y, dw-150, 46,
                   fillColor=WHITE, strokeColor=clr, strokeWidth=1, rx=4, ry=4))
        lines2 = detail.split('\n')
        ty = y + 28
        for line in lines2:
            d.add(String(148, ty, line, fontName="Helvetica", fontSize=7.8, fillColor=GREY))
            ty -= 14

        # Down arrow
        if i < len(stages)-1:
            ay = y - 2
            d.add(Line(dw/2, ay, dw/2, ay-8, strokeColor=GREY, strokeWidth=1.5))
            d.add(Polygon([dw/2-4, ay-6, dw/2+4, ay-6, dw/2, ay-12],
                           fillColor=GREY, strokeColor=GREY))

    return d


# ─── DOCUMENT BUILDER ─────────────────────────────────────────────────────────

def build_pdf(path):
    doc = SimpleDocTemplate(
        path, pagesize=A4,
        leftMargin=2*cm, rightMargin=2*cm,
        topMargin=2.2*cm, bottomMargin=2.2*cm,
        title="Drugs & Cosmetics Act 1940 – Student Handbook",
        author="Professor's Notes"
    )

    story = []
    PW = doc.width   # printable width

    # ══════════════════════ COVER PAGE ════════════════════════════════════════

    class CoverPage(Flowable):
        def wrap(self, aw, ah): return aw, ah
        def draw(self):
            c = self.canv
            pw, ph = A4
            # Gradient background simulation (layered rectangles)
            for i in range(80):
                frac = i / 80
                r = 0.10 + frac * 0.05
                g = 0.14 + frac * 0.02
                b = 0.49 - frac * 0.15
                c.setFillColorRGB(r, g, b)
                c.rect(0, ph * (1 - (i+1)/80), pw, ph/80 + 1, fill=1, stroke=0)

            # Decorative circles
            c.setFillColorRGB(1,1,1,0.06)
            c.circle(pw*0.85, ph*0.78, 90, fill=1, stroke=0)
            c.circle(pw*0.12, ph*0.22, 60, fill=1, stroke=0)
            c.setFillColorRGB(1,1,1,0.04)
            c.circle(pw*0.5, ph*0.5, 160, fill=1, stroke=0)

            # Top accent bar
            c.setFillColor(colors.HexColor("#FFD600"))
            c.rect(0, ph-8, pw, 8, fill=1, stroke=0)

            # Main title
            c.setFillColor(WHITE)
            c.setFont("Helvetica-Bold", 30)
            c.drawCentredString(pw/2, ph*0.72, "DRUGS & COSMETICS")
            c.setFont("Helvetica-Bold", 30)
            c.drawCentredString(pw/2, ph*0.65, "ACT, 1940")

            # Subtitle
            c.setFillColor(colors.HexColor("#FFD600"))
            c.setFont("Helvetica-Bold", 15)
            c.drawCentredString(pw/2, ph*0.58, "Complete Student Handbook")

            # Divider
            c.setStrokeColor(colors.HexColor("#FFD600"))
            c.setLineWidth(2)
            c.line(pw*0.2, ph*0.545, pw*0.8, ph*0.545)

            # Feature pills
            features = [
                "Schedules & Rule Schedules",
                "Import | Manufacture | Sale",
                "Penalty Ladders (Sec 13 & 27)",
                "Flowcharts & Mnemonics",
                "Exam Traps & High-Yield Points"
            ]
            c.setFillColor(colors.HexColor("#E3F2FD"))
            c.setFont("Helvetica", 11)
            for j, feat in enumerate(features):
                c.drawCentredString(pw/2, ph*0.49 - j*0.055*ph, "◆  " + feat)

            # Bottom bar
            c.setFillColor(colors.HexColor("#FFD600"))
            c.rect(0, 0, pw, 48, fill=1, stroke=0)
            c.setFillColor(NAVY)
            c.setFont("Helvetica-Bold", 11)
            c.drawCentredString(pw/2, 28, "Based on Bare Act | CDSCO Official Text | Forensic Medicine 36e (2026)")
            c.setFont("Helvetica", 9)
            c.drawCentredString(pw/2, 12, "For Educational Use Only")

    story.append(CoverPage())
    story.append(PageBreak())

    # ══════════════════════ TABLE OF CONTENTS ═════════════════════════════════
    story.append(ColorBanner("TABLE OF CONTENTS", NAVY, WHITE, 24, 14))
    story.append(Spacer(1, 8))

    toc_data = [
        ("PART 1", "The Schedules — First, Second & Rule Schedules", "3"),
        ("PART 2", "Import of Drugs — Section 10, Licensing, Section 13 Penalties", "5"),
        ("PART 3", "Manufacture of Drugs — Section 18, Schedule M, Special Licences", "8"),
        ("PART 4", "Section 27 Penalty Ladder (3→7→10→Life)", "12"),
        ("PART 5", "Consolidated Manufacture-to-Sale Compliance Flowchart", "14"),
        ("PART 6", "Master Mnemonics Cheatsheet", "15"),
        ("PART 7", "Exam Traps & High-Yield Points", "16"),
    ]
    toc_table = Table(
        [["Part", "Topic", "Pg"]] + toc_data,
        colWidths=[1.5*cm, PW - 3.5*cm, 1.5*cm]
    )
    toc_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), NAVY),
        ('TEXTCOLOR',  (0,0), (-1,0), WHITE),
        ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0), (-1,-1), 10),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LTBLUE]),
        ('GRID',  (0,0), (-1,-1), 0.3, BLUE),
        ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
        ('TOPPADDING',   (0,0), (-1,-1), 6),
        ('BOTTOMPADDING',(0,0), (-1,-1), 6),
        ('LEFTPADDING',  (0,0), (-1,-1), 6),
    ]))
    story.append(toc_table)
    story.append(PageBreak())

    # ══════════════════════ PART 1: SCHEDULES ═════════════════════════════════
    story.append(ColorBanner("PART 1  |  THE SCHEDULES", NAVY, WHITE, 26, 15))
    story.append(Spacer(1, 6))

    story.append(ColorBanner("FIRST SCHEDULE — Books of Standards (Section 3(b))", BLUE, WHITE, 20, 11))
    story.append(Spacer(1, 5))
    story.append(Paragraph(
        "The First Schedule lists the official pharmacopoeias and formularies whose standards define 'standard quality' under the Act. "
        "A drug must conform to the standard in the applicable book listed here.",
        body))
    story.append(Spacer(1, 4))

    first_sch = [
        ["Reference Text", "Applicability"],
        ["Pharmacopoeia of India (IP)", "Primary Indian standard — applies to all IP-listed drugs"],
        ["British Pharmacopoeia (BP)", "Applies to drugs described therein"],
        ["International Pharmacopoeia (WHO)", "WHO standard for internationally traded drugs"],
        ["Extra Pharmacopoeia (Martindale)", "Reference for drugs not in other pharmacopoeias"],
        ["United States Pharmacopeia (USP)", "Applicable where specified"],
        ["British Pharmaceutical Codex (BPC)", "Additional standard for formulations"],
        ["British Veterinary Codex", "Veterinary drugs"],
        ["Ayurvedic Pharmacopoeia of India", "AYUSH Ayurvedic drugs"],
        ["Siddha Vaidya Thirattu / Unani Pharmacopoeia", "AYUSH Siddha & Unani system drugs"],
    ]
    story.append(colored_table(first_sch, [PW*0.42, PW*0.58], BLUE, WHITE, LTBLUE, BLUE))
    story.append(Spacer(1, 5))
    story.append(Paragraph("Mnemonic: <b>I BIG BBA US</b> = IP, BP, International, German, British Vet Codex, British Pharma Codex, Ayurvedic/Siddha/Unani, USP", mnemonic))
    story.append(Spacer(1, 8))

    story.append(ColorBanner("SECOND SCHEDULE — Standards of Quality", TEAL, WHITE, 20, 11))
    story.append(Spacer(1, 5))
    story.append(Paragraph(
        "Lists specific standards (purity, potency, test methods) for drugs manufactured or imported. "
        "Any drug whose standard appears here must fully comply — failing to do so makes it 'not of standard quality' under Section 16. "
        "A fixed-dose combination of a Second Schedule drug with an Ayurvedic drug is explicitly prohibited by Section 10A notifications.",
        body))
    story.append(Spacer(1, 8))

    # Rule Schedules table
    story.append(ColorBanner("HIGH-YIELD RULE SCHEDULES — Drugs & Cosmetics Rules 1945", PURPLE, WHITE, 20, 11))
    story.append(Spacer(1, 5))
    story.append(Paragraph("Mnemonic: <b>C Gets High — H1 too, Just Keep Making Perfectly True eXtra Years</b>", mnemonic))
    story.append(Spacer(1, 5))

    sch_data = [
        ["Sch", "Contents", "Key Requirement"],
        ["C", "Biological & special products\n(vaccines, sera, toxoids, hormones,\nantibiotic injectables)",
         "Enhanced storage/cold chain\nManufacture under stricter GMP\nCentral Licensing Authority (not SLA)"],
        ["C1", "Large-volume parenterals (LVP)", "Separate GMP + separate manufacturing"],
        ["G", "~65 drugs: antihistamines, insulin,\nbleomycin, aminopterine, cytotoxics",
         "Label MUST carry:\n'CAUTION — For use only under\nmedical supervision'"],
        ["H", "Prescription-only drugs (antibiotics,\nsteroids, antihypertensives, etc.)",
         "Only on RMP prescription\nPrescription register mandatory\n'Rx' symbol on label"],
        ["H1", "High-risk Rx drugs: 3rd/4th gen\ncephalosporins, carbapenems,\nfluoroquinolones, anti-TB, antifungals",
         "RED STRIP on label\nPrescription RETAINED 2 years\nNo repeat Rx without fresh prescription"],
        ["J", "54 diseases for which no drug may\nclaim to be a cure (cancer, AIDS,\ndiabetes, etc.)",
         "Any cure claim = misbranding\nProhibited advertising"],
        ["K", "Drugs exempt from Ch IV/IVA in\nsome states (AYUSH, homeopathy)",
         "Limited applicability by state notification"],
        ["M", "GMP standards for premises, plant,\nmachinery, personnel, documentation",
         "Mandatory for all licensed mfrs\n= Indian GMP standard"],
        ["P", "Life period of drugs — storage\nperiod/shelf-life guidelines",
         "Governs expiry dating on labels"],
        ["T", "Standards for surgical dressings,\nbandages, orthopaedic implants",
         "Quality standards for medical devices"],
        ["X", "Habit-forming/psychotropic drugs:\nmorphine, pethidine, fentanyl,\ncodeine formulations",
         "Strict licence (Form 20-A)\nSpecial Rx mandatory\nRecords kept 2 years\nNo advertisement"],
        ["Y", "Requirements for clinical trials\n(data to be submitted for new drugs)",
         "Preclinical + Phase I-III clinical\ndata package for CDSCO approval"],
    ]
    sch_colors = {
        1: (LTBLUE, BLUE),   2: (LTBLUE, BLUE),
        3: (LTGOLD, GOLD),   4: (LTPINK, PINK),
        5: (LTRED, RED),     6: (LTTEAL, TEAL),
        7: (LTGREY, GREY),   8: (LTTEAL, TEAL),
        9: (LTGOLD, GOLD),  10: (LTBLUE, BLUE),
        11: (LTRED, RED),   12: (LTPURPLE, PURPLE),
    }
    t = Table(sch_data, colWidths=[1.0*cm, PW*0.42, PW*0.43])
    ts_style = [
        ('BACKGROUND', (0,0), (-1,0), PURPLE),
        ('TEXTCOLOR',  (0,0), (-1,0), WHITE),
        ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0), (-1,0), 9),
        ('FONTNAME',   (0,1), (-1,-1), 'Helvetica'),
        ('FONTSIZE',   (0,1), (-1,-1), 8),
        ('GRID',  (0,0), (-1,-1), 0.4, PURPLE),
        ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
        ('LEFTPADDING',  (0,0), (-1,-1), 5),
        ('RIGHTPADDING', (0,0), (-1,-1), 5),
        ('TOPPADDING',   (0,0), (-1,-1), 4),
        ('BOTTOMPADDING',(0,0), (-1,-1), 4),
    ]
    for row_i, (bg, _) in sch_colors.items():
        ts_style.append(('BACKGROUND', (0, row_i), (-1, row_i), bg))
        ts_style.append(('FONTNAME',   (0, row_i), (0, row_i), 'Helvetica-Bold'))
        ts_style.append(('TEXTCOLOR',  (0, row_i), (0, row_i), _))
        ts_style.append(('FONTSIZE',   (0, row_i), (0, row_i), 12))
        ts_style.append(('ALIGN',      (0, row_i), (0, row_i), 'CENTER'))
    t.setStyle(TableStyle(ts_style))
    story.append(t)
    story.append(PageBreak())

    # ══════════════════════ PART 2: IMPORT ════════════════════════════════════
    story.append(ColorBanner("PART 2  |  IMPORT OF DRUGS", TEAL, WHITE, 26, 15))
    story.append(Spacer(1, 6))

    story.append(ColorBanner("SECTION 10 — Prohibited Drug Imports", TEAL, WHITE, 20, 11))
    story.append(Spacer(1, 5))
    story.append(Paragraph("Mnemonic: <b>MASque</b> = Misbranded, Adulterated, Spurious, quality-substandard, extra-prohibited", mnemonic))
    story.append(Spacer(1, 5))

    sec10_data = [
        ["Clause", "What is Prohibited"],
        ["10(a)", "Not of standard quality (below First/Second Schedule standard)"],
        ["10(b)", "Misbranded (Section 9 definition)"],
        ["10(c)", "Adulterated (Section 9A definition)"],
        ["10(d)", "Spurious (Section 9B definition)"],
        ["10(ee)", "Cosmetic tested on animals [Post-2014 Fifth Amendment Rules]"],
        ["10(f)", "Without a valid import licence (Form 10)"],
        ["10A",   "Any drug notified by Central Govt as dangerous or lacking\ntherapeutic value (e.g. Nialamide, Practolol, Amidopyrin,\nPhenacetin, Methaqualone, Analgin combinations)"],
    ]
    story.append(colored_table(sec10_data, [1.8*cm, PW-1.8*cm], TEAL, WHITE, LTTEAL, TEAL))
    story.append(Spacer(1, 8))

    story.append(ColorBanner("IMPORT LICENSING FLOWCHART", BLUE, WHITE, 18, 10))
    story.append(Spacer(1, 5))
    fc1 = import_flowchart()
    fc1.width = PW
    story.append(fc1)
    story.append(Spacer(1, 8))

    story.append(ColorBanner("SECTION 13 — PENALTY TABLE (Verified Against Bare Act)", RED, WHITE, 20, 11))
    story.append(Spacer(1, 5))
    story.append(Paragraph(
        "<b>NOTE:</b> Section 13 fine figures are LOW (₹500-₹5,000) — this is a classic exam trap compared to Section 27 lakhs-level fines. "
        "Section 13 figures have NOT been updated by recent amendments.",
        trap_style))
    story.append(Spacer(1, 5))

    sec13_data = [
        ["Clause", "Offence", "Imprisonment", "Fine"],
        ["13(1)(a)", "Import of adulterated/spurious drug\n(Sec 9A/9B) OR animal-tested cosmetic\n(Sec 10, cl. ee)", "Up to 3 YEARS", "Up to ₹5,000"],
        ["13(1)(b)", "Import of any other prohibited drug/\ncosmetic (Sec 10)", "Up to 6 MONTHS", "Up to ₹500\nOR both"],
        ["13(1)(c)", "Import in contravention of\nSection 10A notification", "Up to 3 YEARS", "Up to ₹5,000\nOR both"],
        ["13(2)\nsubsequent", "Repeat conviction under 13(1)(a)", "Up to 7 YEARS", "Up to ₹5,000"],
    ]
    story.append(penalty_table(sec13_data, [1.8*cm, PW*0.40, PW*0.25, PW*0.22]))
    story.append(PageBreak())

    # ══════════════════════ PART 3: MANUFACTURE ═══════════════════════════════
    story.append(ColorBanner("PART 3  |  MANUFACTURE OF DRUGS", BLUE, WHITE, 26, 15))
    story.append(Spacer(1, 6))

    story.append(ColorBanner("SECTION 18 — Prohibitions", BLUE, WHITE, 20, 11))
    story.append(Spacer(1, 5))
    story.append(Paragraph("Mnemonic: <b>No MSA-P-N-L-C</b> = No Misbranded, Spurious, Adulterated, Patent/Proprietary (unlabelled), New drug (unapproved), Licence (non-compliance), Contraband", mnemonic))
    story.append(Spacer(1, 5))

    sec18_data = [
        ["Sub-section", "Prohibition"],
        ["18(a)(i)",   "Drug not of standard quality / misbranded / adulterated / spurious"],
        ["18(a)(ii)",  "Cosmetic not of standard quality / misbranded / adulterated / spurious"],
        ["18(a)(iii)", "Patent/proprietary medicine without displaying true formula or active ingredient list on label"],
        ["18(a)(iv)",  "Drug without a valid licence under Section 18(c)"],
        ["18(a)(v)",   "Drug in contravention of any condition of the licence"],
        ["18(a)(vi)",  "New Drug (Rule 122E) without CDSCO approval"],
        ["18(a)(vii)", "Any drug in violation of notified restriction (Section 26A/26B)"],
        ["18(b)",      "Advertising that any drug cures a Schedule J disease"],
        ["18(c)",      "Manufacture without a licence from the Licensing Authority (Rule 68/69)"],
    ]
    story.append(colored_table(sec18_data, [2.6*cm, PW-2.6*cm], BLUE, WHITE, LTBLUE, BLUE))
    story.append(Spacer(1, 5))
    story.append(Paragraph(
        "<b>Proviso:</b> Manufacture of small quantities for examination, test or analysis is EXEMPT from Sec 18 restrictions "
        "(but still requires a test/analysis licence under Rule 68).",
        note_style))
    story.append(Spacer(1, 8))

    story.append(ColorBanner("SECTION 18 MANUFACTURE PROHIBITION FLOWCHART", BLUE, WHITE, 18, 10))
    story.append(Spacer(1, 5))
    fc2 = manufacture_flowchart()
    fc2.width = PW
    story.append(fc2)
    story.append(Spacer(1, 8))

    story.append(ColorBanner("SCHEDULE M — GMP Requirements", TEAL, WHITE, 20, 11))
    story.append(Spacer(1, 5))
    gmp_data = [
        ["GMP Element", "Key Requirements"],
        ["Buildings & Premises", "Adequate space | Clean room classifications\nSegregated areas: quarantine / sampling / mfg / dispensing / FG"],
        ["Equipment", "Validated & calibrated | Stainless steel where required | Cleaned & logged"],
        ["Personnel", "Qualified Person (QP) mandatory | Training records | Health surveillance"],
        ["Sanitation", "SOPs for cleaning | Pest control | Gowning procedures"],
        ["Documentation", "Batch Manufacturing Records (BMR) | SOPs | Batch Packing Records"],
        ["Quality Control", "In-process testing | Release testing\nRef samples: 3 yrs (no expiry) | 3 months post-expiry"],
        ["Self-Inspection", "Periodic internal audits | Documented CAPA"],
        ["Complaints & Recalls", "Written procedures mandatory | Traceability to batch"],
    ]
    story.append(colored_table(gmp_data, [PW*0.30, PW*0.70], TEAL, WHITE, LTTEAL, TEAL))
    story.append(Spacer(1, 8))

    story.append(ColorBanner("FOUR SPECIAL LICENCE TYPES  [TeNo-Lo-Re]", PURPLE, WHITE, 20, 11))
    story.append(Spacer(1, 5))
    story.append(Paragraph("Mnemonic: <b>TeNo-Lo-Re</b> = Test/analysis, New drug, Loan licence, Repacking licence", mnemonic))
    story.append(Spacer(1, 5))

    lic4_data = [
        ["Licence", "Form", "Who Applies", "Key Features"],
        ["Test/Analysis\nLicence", "Form 11\n(import)\nForm 24 cat.\n(mfg)", "Research labs\nAnalytical labs",
         "Small quantities only\nNon-commercial use\nTest facility specified in licence\nInspector access MANDATORY"],
        ["New Drug\nLicence", "Form 44", "Manufacturer of\na New Drug\n(Rule 122E)", "Phase I-III clinical trial data\n(Schedule Y) compulsory\nCDSCO Central approval ONLY\n(NOT State SLA)"],
        ["Loan Licence", "Form 25A\n(Rule 69A)", "Company with\nformula but no\nown plant",
         "Uses licensor's premises + equipment\nLicensor must hold valid Form 25\nAuto-cancelled if licensor's\nForm 25 cancelled/suspended"],
        ["Repacking\nLicence", "Form 25B\n(Rule 74A)", "Company buying\nbulk drug for\nrepackaging",
         "Qualified competent person\nmust supervise at ALL times\nOwn testing facility required\nNo alteration of drug substance"],
    ]
    t4 = Table(lic4_data, colWidths=[2.3*cm, 1.8*cm, 2.5*cm, PW-6.6*cm])
    t4.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), PURPLE),
        ('TEXTCOLOR',  (0,0), (-1,0), WHITE),
        ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0), (-1,0), 9),
        ('BACKGROUND', (0,1), (-1,1), LTTEAL),
        ('BACKGROUND', (0,2), (-1,2), LTORANGE),
        ('BACKGROUND', (0,3), (-1,3), LTBLUE),
        ('BACKGROUND', (0,4), (-1,4), LTPURPLE),
        ('FONTNAME',   (0,1), (-1,-1), 'Helvetica'),
        ('FONTSIZE',   (0,1), (-1,-1), 8),
        ('GRID',  (0,0), (-1,-1), 0.4, PURPLE),
        ('VALIGN',(0,0),(-1,-1),'TOP'),
        ('LEFTPADDING',  (0,0), (-1,-1), 5),
        ('RIGHTPADDING', (0,0), (-1,-1), 5),
        ('TOPPADDING',   (0,0), (-1,-1), 5),
        ('BOTTOMPADDING',(0,0), (-1,-1), 5),
    ]))
    story.append(t4)
    story.append(Spacer(1, 8))

    story.append(ColorBanner("SPECIAL LICENCE COMPARISON FLOWCHART", PURPLE, WHITE, 18, 10))
    story.append(Spacer(1, 5))
    fc3 = special_licence_flowchart()
    fc3.width = PW
    story.append(fc3)
    story.append(PageBreak())

    # ══════════════════════ PART 4: SECTION 27 ════════════════════════════════
    story.append(ColorBanner("PART 4  |  SECTION 27 PENALTY LADDER", RED, WHITE, 26, 15))
    story.append(Spacer(1, 6))
    story.append(Paragraph("Mnemonic: <b>3-7-10-LIFE</b> — remember the MINIMUM sentences!", mnemonic))
    story.append(Spacer(1, 8))

    story.append(ColorBanner("SECTION 27 PENALTY LADDER FLOWCHART", RED, WHITE, 18, 10))
    story.append(Spacer(1, 5))
    fc4 = penalty_ladder_flowchart()
    fc4.width = PW
    story.append(fc4)
    story.append(Spacer(1, 10))

    story.append(ColorBanner("SECTION 27 — Detailed Penalty Table (Verified: CDSCO + India Code)", RED, WHITE, 18, 10))
    story.append(Spacer(1, 6))

    s27_data = [
        ["Clause", "Offence", "Min Imprisonment", "Max Imprisonment", "Fine"],
        ["27(d)", "Any other contravention\n(labelling error, licence\ncondition breach)", "—", "1 Year",
         "≥ ₹20,000\n(Court may reduce\non recorded reasons)"],
        ["27(c)", "Adulterated drug (Sec 17A)\nNOT causing death\nor grievous hurt", "1 Year", "3 Years",
         "≥ ₹50,000"],
        ["27(b)", "Spurious drug (Sec 17B)\nNOT causing death\nor grievous hurt",
         "7 Years\n(Proviso: Court may\nimpose < 7 yrs)", "LIFE",
         "≥ ₹3 lakh\nOR 3× drug value\n(whichever more)"],
        ["27(a)\n★ HIGHEST ★", "Adulterated/Spurious drug\nWHICH CAUSES or IS\nLIKELY TO CAUSE DEATH\nor GRIEVOUS HARM",
         "10 Years\n(Proviso: Court may\nimpose < 10 yrs)", "LIFE",
         "≥ ₹10 lakh\nOR 3× drug value\n(whichever more)"],
    ]
    ts27 = TableStyle([
        ('BACKGROUND', (0,0), (-1,0), RED),
        ('TEXTCOLOR',  (0,0), (-1,0), WHITE),
        ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0), (-1,0), 8.5),
        ('BACKGROUND', (0,1), (-1,1), LTGREY),
        ('BACKGROUND', (0,2), (-1,2), LTORANGE),
        ('BACKGROUND', (0,3), (-1,3), LTRED),
        ('BACKGROUND', (0,4), (-1,4), colors.HexColor("#FFCDD2")),
        ('FONTNAME',   (0,4), (-1,4), 'Helvetica-Bold'),
        ('TEXTCOLOR',  (0,4), (-1,4), RED),
        ('FONTNAME',   (0,1), (-1,-1), 'Helvetica'),
        ('FONTSIZE',   (0,1), (-1,-1), 8),
        ('GRID',  (0,0), (-1,-1), 0.4, RED),
        ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
        ('LEFTPADDING',  (0,0), (-1,-1), 5),
        ('RIGHTPADDING', (0,0), (-1,-1), 5),
        ('TOPPADDING',   (0,0), (-1,-1), 5),
        ('BOTTOMPADDING',(0,0), (-1,-1), 5),
    ])
    t27 = Table(s27_data, colWidths=[1.8*cm, PW*0.33, PW*0.20, PW*0.20, PW*0.22])
    t27.setStyle(ts27)
    story.append(t27)
    story.append(Spacer(1, 8))

    story.append(ColorBanner("SECTION 30 — Subsequent Offence Enhancement", RED, WHITE, 18, 10))
    story.append(Spacer(1, 5))
    s30_data = [
        ["Previous Conviction", "Enhanced Repeat Punishment"],
        ["Under Sec 27(b)\n(spurious, no death)", "NOT < 7 yrs, up to 10 Years\n+ Fine ≥ ₹2 lakh"],
        ["Under Sec 27(c)\n(adulterated, no death)", "NOT < 10 yrs, up to LIFE\n+ Fine ≥ ₹3 lakh"],
        ["Under Sec 27(d)\n(other contravention)", "NOT < 2 yrs, up to 4 Years\nOR Fine ≥ ₹50,000, or both"],
    ]
    story.append(colored_table(s30_data, [PW*0.45, PW*0.55], RED, WHITE, LTRED, RED))
    story.append(PageBreak())

    # ══════════════════════ PART 5: MFG TO SALE FLOWCHART ════════════════════
    story.append(ColorBanner("PART 5  |  CONSOLIDATED MANUFACTURE-TO-SALE FLOWCHART", GOLD, NAVY, 26, 14))
    story.append(Spacer(1, 6))
    story.append(Paragraph("Mnemonic: <b>MASt-P-New</b> = Manufacture lic | Approved premises | Standard quality | testing | Packaging | New drug approval", mnemonic))
    story.append(Spacer(1, 8))

    fc5 = mfg_to_sale_flowchart()
    fc5.width = PW
    story.append(fc5)
    story.append(PageBreak())

    # ══════════════════════ PART 6: MNEMONICS ═════════════════════════════════
    story.append(ColorBanner("PART 6  |  MASTER MNEMONICS CHEATSHEET", PURPLE, WHITE, 26, 15))
    story.append(Spacer(1, 6))

    mnemonics_data = [
        ["Mnemonic", "Full Form", "Covers"],
        ["MASque", "Misbranded, Adulterated,\nSpurious, quality-substandard,\nextra-prohibited", "Prohibited drug categories\n(Sec 10 & Sec 18)"],
        ["MASt-P-New", "Manufacture lic, Approved premises,\nStandard drugs, testing,\nPackaging/labelling, New drug lic",
         "Full compliance checklist\nSec 18 onwards"],
        ["TeNo-Lo-Re", "Test/analysis licence,\nNew drug licence,\nLoan licence,\nRepacking licence",
         "4 Special licence types\n(Forms 11/44/25A/25B)"],
        ["3-7-10-Life", "3 yrs (Sec 13/27c category),\n7 yrs min (Sec 27b spurious),\n10 yrs min (Sec 27a death),\nLife maximum",
         "Penalty ladder\nSection 27 + 30"],
        ["C Gets High\nH1 too", "C=Biological, G=Caution label,\nH=Rx only, H1=Red strip",
         "Prescription schedule\nrequirements"],
        ["J bans K M P T X Y", "J=No-cure claims, K=Exempt,\nM=GMP, P=Shelf life,\nT=Surgical, X=Habit-forming,\nY=Clinical trial data",
         "All high-yield Rule Schedules"],
        ["I BIG BBA US", "IP, BP, International, German,\nBritish Vet, British Pharma Codex,\nAyurvedic/Siddha/Unani, USP",
         "First Schedule\nStandard books"],
    ]
    mn_t = Table(mnemonics_data, colWidths=[2.8*cm, PW*0.42, PW*0.38])
    mn_t.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), PURPLE),
        ('TEXTCOLOR',  (0,0), (-1,0), WHITE),
        ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0), (-1,0), 9.5),
        ('FONTNAME',   (0,1), (0,-1), 'Helvetica-Bold'),
        ('TEXTCOLOR',  (0,1), (0,-1), PURPLE),
        ('FONTSIZE',   (0,1), (0,-1), 11),
        ('FONTNAME',   (1,1), (-1,-1), 'Helvetica'),
        ('FONTSIZE',   (1,1), (-1,-1), 8.5),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LTPURPLE, WHITE]),
        ('GRID',  (0,0), (-1,-1), 0.4, PURPLE),
        ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
        ('LEFTPADDING',  (0,0), (-1,-1), 6),
        ('RIGHTPADDING', (0,0), (-1,-1), 6),
        ('TOPPADDING',   (0,0), (-1,-1), 6),
        ('BOTTOMPADDING',(0,0), (-1,-1), 6),
    ]))
    story.append(mn_t)
    story.append(PageBreak())

    # ══════════════════════ PART 7: EXAM TRAPS ════════════════════════════════
    story.append(ColorBanner("PART 7  |  EXAM TRAPS & HIGH-YIELD POINTS", RED, WHITE, 26, 15))
    story.append(Spacer(1, 6))

    traps = [
        ("1. Section 27 vs Section 13 Fines",
         "Sec 27 fines = LAKHS (₹10 lakh for death-causing drugs). Sec 13 fines = TINY (₹500-₹5,000). "
         "Both are frequently tested side-by-side. The small Section 13 fine amounts have NOT been updated by recent amendments."),
        ("2. Loan Licence (Form 25A) Auto-Cancellation",
         "If the licensor's Form 25 is cancelled or suspended → the loan licensee's Form 25A is AUTOMATICALLY cancelled. "
         "No separate notice/procedure needed. (Rule 74B)"),
        ("3. Schedule H1 = RED STRIP (not Red Box/Cross)",
         "H1 requires a RED STRIP across the top of the label. Prescription must be RETAINED by the chemist for 2 years. "
         "Cannot be dispensed again without a FRESH prescription. Introduced by 2013 amendment to curb antibiotic resistance."),
        ("4. New Drug Approval = CDSCO Central Only",
         "New Drug (Rule 122E) licence (Form 44) requires Central Government/CDSCO approval — NOT State Licensing Authority. "
         "This is a classic MCQ distractor."),
        ("5. Section 18 Proviso — Test/Analysis Exemption",
         "Small quantities manufactured ONLY for examination, test or analysis are EXEMPT from Section 18 prohibitions. "
         "BUT a test/analysis licence under Rule 68 is still required."),
        ("6. Section 27(a) Threshold — 'Likely to Cause'",
         "Section 27(a) (10 years to life) applies when a drug IS LIKELY TO CAUSE death or grievous harm — not just when death actually occurs. "
         "Prosecution does not need to wait for actual death."),
        ("7. Cognizable & Non-Bailable Offences",
         "Spurious/adulterated drugs that CAUSE DEATH are COGNIZABLE (police can arrest without warrant) and NON-BAILABLE. "
         "This is a distinct feature vs. other offences under the Act."),
        ("8. Schedule C Drugs — Central, Not State, Authority",
         "Biological products (Schedule C) are licensed by the CENTRAL Licensing Authority (CDSCO), not the State Licensing Authority, "
         "unlike most other allopathic drugs."),
        ("9. No Advertisement of Sch H / H1 / X",
         "Advertisement of Schedule H, H1, or X drugs requires PRIOR SANCTION of the Central Government (Rule 74). "
         "This is absolute — no advertisement without this sanction."),
        ("10. Reference Sample Retention Times",
         "3 YEARS from date of manufacture (if NO expiry date on label). "
         "3 MONTHS BEYOND EXPIRY DATE (if expiry date is stated on label). "
         "Frequently tested in MCQs — do not confuse these two figures."),
        ("11. Section 10A vs Section 10",
         "Section 10 = statutory prohibition of specific drug classes (misbranded, adulterated, spurious, etc.). "
         "Section 10A = Central Govt's POWER to prohibit ANY drug by notification (e.g., analgin combinations, phenacetin). "
         "Section 10A requires a Gazette notification; Section 10 applies automatically."),
        ("12. Fixed Dose Combination (FDC) Trap",
         "A fixed-dose combination of a Second Schedule drug with an Ayurvedic drug is PROHIBITED under Section 10A notifications — "
         "even if both drugs are individually permitted. Examiners love this nuance."),
    ]

    for i, (heading, content) in enumerate(traps):
        row_bg = LTRED if i % 2 == 0 else LTORANGE
        trap_data = [[heading, content]]
        tr = Table(trap_data, colWidths=[PW*0.34, PW*0.66])
        tr.setStyle(TableStyle([
            ('BACKGROUND', (0,0), (0,0), RED if i % 2 == 0 else ORANGE),
            ('TEXTCOLOR',  (0,0), (0,0), WHITE),
            ('BACKGROUND', (1,0), (1,0), row_bg),
            ('TEXTCOLOR',  (1,0), (1,0), GREY),
            ('FONTNAME',   (0,0), (0,0), 'Helvetica-Bold'),
            ('FONTNAME',   (1,0), (1,0), 'Helvetica'),
            ('FONTSIZE',   (0,0), (-1,0), 8.5),
            ('VALIGN',     (0,0), (-1,0), 'MIDDLE'),
            ('GRID',       (0,0), (-1,-1), 0.3, RED),
            ('LEFTPADDING',  (0,0), (-1,-1), 6),
            ('RIGHTPADDING', (0,0), (-1,-1), 6),
            ('TOPPADDING',   (0,0), (-1,-1), 5),
            ('BOTTOMPADDING',(0,0), (-1,-1), 5),
        ]))
        story.append(tr)
        story.append(Spacer(1, 3))

    story.append(Spacer(1, 12))

    # Footer disclaimer
    story.append(HRFlowable(width=PW, thickness=1, color=NAVY))
    story.append(Spacer(1, 4))
    story.append(Paragraph(
        "Sources: CDSCO Official PDF of Drugs & Cosmetics Act & Rules 2016 | India Code Bare Act (indiacode.nic.in) | "
        "Karnataka Drugs Control Dept Penalty Table 2025 | The Essentials of Forensic Medicine & Toxicology 36e (2026) | "
        "For Educational Use Only",
        footer_sty))

    # ─── PAGE NUMBERING ───────────────────────────────────────────────────────
    def add_page_decorations(canvas, doc):
        canvas.saveState()
        pw, ph = A4
        # Top bar
        canvas.setFillColor(NAVY)
        canvas.rect(0, ph-14, pw, 14, fill=1, stroke=0)
        canvas.setFillColor(WHITE)
        canvas.setFont("Helvetica-Bold", 7)
        canvas.drawCentredString(pw/2, ph-10, "Drugs & Cosmetics Act 1940 — Student Handbook")
        # Bottom bar
        canvas.setFillColor(LTBLUE)
        canvas.rect(0, 0, pw, 16, fill=1, stroke=0)
        canvas.setFillColor(NAVY)
        canvas.setFont("Helvetica", 7.5)
        canvas.drawString(2*cm, 5, "For Educational Use Only")
        canvas.drawRightString(pw - 2*cm, 5, f"Page {doc.page}")
        canvas.restoreState()

    doc.build(story, onFirstPage=add_page_decorations, onLaterPages=add_page_decorations)
    print(f"PDF generated: {path}")


if __name__ == "__main__":
    out = "/home/daytona/workspace/dca-handbook/DCA_1940_Student_Handbook.pdf"
    build_pdf(out)
Running Command

cd /home/daytona/workspace/dca-handbook && python3 generate_handbook.py 2>&1

Editing File

~/dca-handbook/generate_handbook.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/dca-handbook/generate_handbook.py'
Running Command

cd /home/daytona/workspace/dca-handbook && python3 generate_handbook.py 2>&1

Running Command

ls -lh /home/daytona/workspace/dca-handbook/DCA_1940_Student_Handbook.pdf

Your colorful student handbook PDF is ready!

DCA 1940 Student Handbook

PDF Document · PDF


Here is what the handbook contains across 7 fully formatted, color-coded parts:
PartContent
Cover PageFull-color gradient cover with gold accent bar
Table of ContentsNavy-blue styled TOC with page references
Part 1First & Second Schedules + all Rule Schedules (C, G, H, H1, J, K, M, P, T, X, Y) — color-coded table with each schedule highlighted individually
Part 2Section 10 prohibited classes table + Import Licensing Flowchart (with diamond decision nodes, colored boxes, arrows) + Section 13 Penalty Table in red
Part 3Section 18 Prohibitions table + Manufacture Prohibition Flowchart + Schedule M GMP requirements + Four Special Licence table + TeNo-Lo-Re Flowchart
Part 4Section 27 Penalty Ladder Flowchart (numbered rungs from grey → orange → red → dark red) + detailed penalty table + Section 30 subsequent offence table
Part 5Consolidated Manufacture-to-Sale Flowchart (7-stage A through G with colored stage badges)
Part 6Master Mnemonics Cheatsheet (MASque, MASt-P-New, TeNo-Lo-Re, 3-7-10-Life, etc.)
Part 712 Exam Traps & High-Yield Points in alternating red/orange highlighted rows
Every page has a navy header bar and light blue footer with page numbers. All flowcharts are drawn natively in the PDF with colored boxes, diamond decision nodes, and labeled arrows.
This is a shared conversation. Sign in to Orris to start your own chat.